Index: projects/clang360-import/contrib/compiler-rt/lib/asan/README.txt =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/README.txt (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/README.txt (revision 279194) @@ -1,28 +1,26 @@ AddressSanitizer RT ================================ -This directory contains sources of the AddressSanitizer (asan) runtime library. -We are in the process of integrating AddressSanitizer with LLVM, stay tuned. +This directory contains sources of the AddressSanitizer (ASan) runtime library. Directory structure: README.txt : This file. Makefile.mk : File for make-based build. CMakeLists.txt : File for cmake-based build. asan_*.{cc,h} : Sources of the asan runtime library. scripts/* : Helper scripts. tests/* : ASan unit tests. Also ASan runtime needs the following libraries: lib/interception/ : Machinery used to intercept function calls. -lib/sanitizer_common/ : Code shared between ASan and TSan. +lib/sanitizer_common/ : Code shared between various sanitizers. -Currently ASan runtime can be built by both make and cmake build systems. -(see compiler-rt/make and files Makefile.mk for make-based build and -files CMakeLists.txt for cmake-based build). +ASan runtime currently also embeds part of LeakSanitizer runtime for +leak detection (lib/lsan/lsan_common.{cc,h}). -ASan unit and output tests work only with cmake. You may run this -command from the root of your cmake build tree: +ASan runtime can only be built by CMake. You can run ASan tests +from the root of your CMake build tree: make check-asan For more instructions see: http://code.google.com/p/address-sanitizer/wiki/HowToBuild Index: projects/clang360-import/contrib/compiler-rt/lib/asan/asan_flags.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/asan_flags.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/asan_flags.cc (revision 279194) @@ -1,141 +1,160 @@ //===-- 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" 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 } -void RegisterAsanFlags(FlagParser *parser, Flags *f) { +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(Flags *f) { - FlagParser parser; - RegisterAsanFlags(&parser, f); - RegisterCommonFlags(&parser); - +void InitializeFlags() { + // Set the default values and prepare for parsing ASan and common flags. SetCommonFlagsDefaults(); { CommonFlags cf; cf.CopyFrom(*common_flags()); cf.detect_leaks = CAN_SANITIZE_LEAKS; cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH"); cf.malloc_context_size = kDefaultMallocContextSize; cf.intercept_tls_get_addr = true; OverrideCommonFlags(cf); } - - const int kDefaultQuarantineSizeMb = (ASAN_LOW_MEMORY) ? 1UL << 6 : 1UL << 8; + Flags *f = flags(); f->SetDefaults(); - // Override from compile definition. - const char *compile_def = MaybeUseAsanDefaultOptionsCompileDefinition(); - parser.ParseString(compile_def); + FlagParser asan_parser; + RegisterAsanFlags(&asan_parser, f); + RegisterCommonFlags(&asan_parser); + // Set the default values and prepare for parsing LSan 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 + + // Override from ASan compile definition. + const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition(); + asan_parser.ParseString(asan_compile_def); + // Override from user-specified string. - const char *default_options = MaybeCallAsanDefaultOptions(); - parser.ParseString(default_options); + const char *asan_default_options = MaybeCallAsanDefaultOptions(); + asan_parser.ParseString(asan_default_options); // Override from command line. - const char *env = GetEnv("ASAN_OPTIONS"); - if (env) parser.ParseString(env); + asan_parser.ParseString(GetEnv("ASAN_OPTIONS")); +#if CAN_SANITIZE_LEAKS + lsan_parser.ParseString(GetEnv("LSAN_OPTIONS")); +#endif // Let activation flags override current settings. On Android they come // from a system property. On other platforms this is no-op. if (!flags()->start_deactivated) { char buf[100]; GetExtraActivationFlags(buf, sizeof(buf)); - parser.ParseString(buf); + asan_parser.ParseString(buf); } SetVerbosity(common_flags()->verbosity); // TODO(eugenis): dump all flags at verbosity>=2? if (Verbosity()) ReportUnrecognizedFlags(); - if (common_flags()->help) parser.PrintFlagDescriptions(); + 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) + if (f->quarantine_size_mb < 0) { + const int kDefaultQuarantineSizeMb = + (ASAN_LOW_MEMORY) ? 1UL << 6 : 1UL << 8; f->quarantine_size_mb = kDefaultQuarantineSizeMb; + } } } // namespace __asan #if !SANITIZER_SUPPORTS_WEAK_HOOKS extern "C" { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char* __asan_default_options() { return ""; } } // extern "C" #endif Index: projects/clang360-import/contrib/compiler-rt/lib/asan/asan_flags.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/asan_flags.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/asan_flags.h (revision 279194) @@ -1,49 +1,49 @@ //===-- asan_flags.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 runtime flags. //===----------------------------------------------------------------------===// #ifndef ASAN_FLAGS_H #define ASAN_FLAGS_H #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_flag_parser.h" // ASan flag values can be defined in four ways: // 1) initialized with default values at startup. // 2) overriden during compilation of ASan runtime by providing // compile definition ASAN_DEFAULT_OPTIONS. // 3) overriden from string returned by user-specified function // __asan_default_options(). // 4) overriden from env variable ASAN_OPTIONS. // 5) overriden during ASan activation (for now used on Android only). namespace __asan { struct Flags { #define ASAN_FLAG(Type, Name, DefaultValue, Description) Type Name; #include "asan_flags.inc" #undef ASAN_FLAG void SetDefaults(); }; extern Flags asan_flags_dont_use_directly; inline Flags *flags() { return &asan_flags_dont_use_directly; } -void RegisterAsanFlags(FlagParser *parser, Flags *f); -void InitializeFlags(Flags *f); + +void InitializeFlags(); } // namespace __asan #endif // ASAN_FLAGS_H Index: projects/clang360-import/contrib/compiler-rt/lib/asan/asan_flags.inc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/asan_flags.inc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/asan_flags.inc (revision 279194) @@ -1,144 +1,145 @@ //===-- 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, 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 intinsics.") ASAN_FLAG(bool, mac_ignore_invalid_free, false, "Ignore invalid free() calls to work around some bugs. Used on OS X " "only.") ASAN_FLAG(bool, detect_stack_use_after_return, false, "Enables stack-use-after-return checking at run-time.") ASAN_FLAG(int, min_uar_stack_size_log, 16, // We can't do smaller anyway. "Minimum fake stack size log.") ASAN_FLAG(int, max_uar_stack_size_log, 20, // 1Mb per size class, i.e. ~11Mb per thread "Maximum fake stack size log.") ASAN_FLAG(bool, uar_noreserve, false, "Use mmap with 'noreserve' flag to allocate fake stack.") ASAN_FLAG( int, max_malloc_fill_size, 0x1000, // By default, fill only the first 4K. "ASan allocator flag. max_malloc_fill_size is the maximal amount of " "bytes that will be filled with malloc_fill_byte on malloc.") ASAN_FLAG(int, malloc_fill_byte, 0xbe, "Value used to fill the newly allocated memory.") ASAN_FLAG(int, exitcode, ASAN_DEFAULT_FAILURE_EXITCODE, "Override the program exit status if the tool found an error.") 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, abort_on_error, false, "If set, the tool calls abort() instead of _exit() after printing the " "error report.") 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, 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://code.google.com/p/address-sanitizer/issues/detail?id=131 // https://code.google.com/p/address-sanitizer/issues/detail?id=309 // TODO(glider,timurrrr): Fix known issues and enable this back. ASAN_FLAG(bool, alloc_dealloc_mismatch, (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0), "Report errors on malloc/delete, new/free, new/delete[], etc.") ASAN_FLAG(bool, new_delete_type_mismatch, true, "Report errors on mismatch betwen size of new and delete.") ASAN_FLAG(bool, strict_memcmp, true, "If true, assume that memcmp(p1, p2, n) always reads n bytes before " "comparing p1 and p2.") 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://code.google.com/p/address-sanitizer/wiki/ContainerOverflow") 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(const char *, suppressions, "", "Suppressions file name.") Index: projects/clang360-import/contrib/compiler-rt/lib/asan/asan_globals.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/asan_globals.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/asan_globals.cc (revision 279194) @@ -1,293 +1,309 @@ //===-- asan_globals.cc ---------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Handle globals. //===----------------------------------------------------------------------===// #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_mapping.h" #include "asan_poisoning.h" #include "asan_report.h" #include "asan_stack.h" #include "asan_stats.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_mutex.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_stackdepot.h" namespace __asan { typedef __asan_global Global; struct ListOfGlobals { const Global *g; ListOfGlobals *next; }; static BlockingMutex mu_for_globals(LINKER_INITIALIZED); static LowLevelAllocator allocator_for_globals; static ListOfGlobals *list_of_all_globals; static const int kDynamicInitGlobalsInitialCapacity = 512; struct DynInitGlobal { Global g; bool initialized; }; typedef InternalMmapVector VectorOfGlobals; // Lazy-initialized and never deleted. static VectorOfGlobals *dynamic_init_globals; // We want to remember where a certain range of globals was registered. struct GlobalRegistrationSite { u32 stack_id; Global *g_first, *g_last; }; typedef InternalMmapVector GlobalRegistrationSiteVector; static GlobalRegistrationSiteVector *global_registration_site_vector; ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) { FastPoisonShadow(g->beg, g->size_with_redzone, value); } ALWAYS_INLINE void PoisonRedZones(const Global &g) { uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY); FastPoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size, kAsanGlobalRedzoneMagic); if (g.size != aligned_size) { FastPoisonShadowPartialRightRedzone( g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY), g.size % SHADOW_GRANULARITY, SHADOW_GRANULARITY, kAsanGlobalRedzoneMagic); } } const uptr kMinimalDistanceFromAnotherGlobal = 64; bool IsAddressNearGlobal(uptr addr, const __asan_global &g) { if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false; if (addr >= g.beg + g.size_with_redzone) return false; return true; } static void ReportGlobal(const Global &g, const char *prefix) { Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n", prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name, g.module_name, g.has_dynamic_init); if (g.location) { Report(" location (%p): name=%s[%p], %d %d\n", g.location, g.location->filename, g.location->filename, g.location->line_no, g.location->column_no); } } static bool DescribeOrGetInfoIfGlobal(uptr addr, uptr size, bool print, Global *output_global) { if (!flags()->report_globals) return false; BlockingMutexLock lock(&mu_for_globals); bool res = false; for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { const Global &g = *l->g; if (print) { if (flags()->report_globals >= 2) ReportGlobal(g, "Search"); res |= DescribeAddressRelativeToGlobal(addr, size, g); } else { if (IsAddressNearGlobal(addr, g)) { CHECK(output_global); *output_global = g; return true; } } } return res; } bool DescribeAddressIfGlobal(uptr addr, uptr size) { return DescribeOrGetInfoIfGlobal(addr, size, /* print */ true, /* output_global */ nullptr); } bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) { Global g = {}; if (DescribeOrGetInfoIfGlobal(addr, /* size */ 1, /* print */ false, &g)) { internal_strncpy(descr->name, g.name, descr->name_size); descr->region_address = g.beg; descr->region_size = g.size; descr->region_kind = "global"; return true; } return false; } u32 FindRegistrationSite(const Global *g) { CHECK(global_registration_site_vector); for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) { GlobalRegistrationSite &grs = (*global_registration_site_vector)[i]; if (g >= grs.g_first && g <= grs.g_last) return grs.stack_id; } return 0; } // Register a global variable. // This function may be called more than once for every global // so we store the globals in a map. static void RegisterGlobal(const Global *g) { CHECK(asan_inited); if (flags()->report_globals >= 2) ReportGlobal(*g, "Added"); CHECK(flags()->report_globals); CHECK(AddrIsInMem(g->beg)); CHECK(AddrIsAlignedByGranularity(g->beg)); CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); if (flags()->detect_odr_violation) { // Try detecting ODR (One Definition Rule) violation, i.e. the situation // where two globals with the same name are defined in different modules. if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) { // This check may not be enough: if the first global is much larger // the entire redzone of the second global may be within the first global. for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { if (g->beg == l->g->beg && (flags()->detect_odr_violation >= 2 || g->size != l->g->size)) ReportODRViolation(g, FindRegistrationSite(g), l->g, FindRegistrationSite(l->g)); } } } if (CanPoisonMemory()) PoisonRedZones(*g); ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals; l->g = g; l->next = list_of_all_globals; list_of_all_globals = l; if (g->has_dynamic_init) { if (dynamic_init_globals == 0) { dynamic_init_globals = new(allocator_for_globals) VectorOfGlobals(kDynamicInitGlobalsInitialCapacity); } DynInitGlobal dyn_global = { *g, false }; dynamic_init_globals->push_back(dyn_global); } } static void UnregisterGlobal(const Global *g) { CHECK(asan_inited); + if (flags()->report_globals >= 2) + ReportGlobal(*g, "Removed"); CHECK(flags()->report_globals); CHECK(AddrIsInMem(g->beg)); CHECK(AddrIsAlignedByGranularity(g->beg)); CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); if (CanPoisonMemory()) PoisonShadowForGlobal(g, 0); // We unpoison the shadow memory for the global but we do not remove it from // the list because that would require O(n^2) time with the current list // implementation. It might not be worth doing anyway. } void StopInitOrderChecking() { BlockingMutexLock lock(&mu_for_globals); if (!flags()->check_initialization_order || !dynamic_init_globals) return; flags()->check_initialization_order = false; for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; const Global *g = &dyn_g.g; // Unpoison the whole global. PoisonShadowForGlobal(g, 0); // Poison redzones back. PoisonRedZones(*g); } } + +#if SANITIZER_WINDOWS // Should only be called on Windows. +SANITIZER_INTERFACE_ATTRIBUTE +void UnregisterGlobalsInRange(void *beg, void *end) { + if (!flags()->report_globals) + return; + BlockingMutexLock lock(&mu_for_globals); + for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { + void *address = (void *)l->g->beg; + if (beg <= address && address < end) + UnregisterGlobal(l->g); + } +} +#endif } // namespace __asan // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT // Register an array of globals. void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; GET_STACK_TRACE_FATAL_HERE; u32 stack_id = StackDepotPut(stack); BlockingMutexLock lock(&mu_for_globals); if (!global_registration_site_vector) global_registration_site_vector = new(allocator_for_globals) GlobalRegistrationSiteVector(128); GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]}; global_registration_site_vector->push_back(site); if (flags()->report_globals >= 2) { PRINT_CURRENT_STACK(); Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]); } for (uptr i = 0; i < n; i++) { RegisterGlobal(&globals[i]); } } // Unregister an array of globals. // We must do this when a shared objects gets dlclosed. void __asan_unregister_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; BlockingMutexLock lock(&mu_for_globals); for (uptr i = 0; i < n; i++) { UnregisterGlobal(&globals[i]); } } // This method runs immediately prior to dynamic initialization in each TU, // when all dynamically initialized globals are unpoisoned. This method // poisons all global variables not defined in this TU, so that a dynamic // initializer can only touch global variables in the same TU. void __asan_before_dynamic_init(const char *module_name) { if (!flags()->check_initialization_order || !CanPoisonMemory()) return; bool strict_init_order = flags()->strict_init_order; CHECK(dynamic_init_globals); CHECK(module_name); CHECK(asan_inited); BlockingMutexLock lock(&mu_for_globals); if (flags()->report_globals >= 3) Printf("DynInitPoison module: %s\n", module_name); for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; const Global *g = &dyn_g.g; if (dyn_g.initialized) continue; if (g->module_name != module_name) PoisonShadowForGlobal(g, kAsanInitializationOrderMagic); else if (!strict_init_order) dyn_g.initialized = true; } } // This method runs immediately after dynamic initialization in each TU, when // all dynamically initialized globals except for those defined in the current // TU are poisoned. It simply unpoisons all dynamically initialized globals. void __asan_after_dynamic_init() { if (!flags()->check_initialization_order || !CanPoisonMemory()) return; CHECK(asan_inited); BlockingMutexLock lock(&mu_for_globals); // FIXME: Optionally report that we're unpoisoning globals from a module. for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; const Global *g = &dyn_g.g; if (!dyn_g.initialized) { // Unpoison the whole global. PoisonShadowForGlobal(g, 0); // Poison redzones back. PoisonRedZones(*g); } } } Index: projects/clang360-import/contrib/compiler-rt/lib/asan/asan_interface_internal.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/asan_interface_internal.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/asan_interface_internal.h (revision 279194) @@ -1,182 +1,185 @@ //===-- 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 can be included by the instrumented program to fetch -// data (mostly allocator statistics) from ASan runtime library. +// 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; 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. // Please note that __asan_init is a macro that is replaced with // __asan_init_vXXX at compile-time. SANITIZER_INTERFACE_ATTRIBUTE void __asan_init(); // 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. }; // 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(); // 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); SANITIZER_INTERFACE_ATTRIBUTE int __asan_set_error_exit_code(int exit_code); SANITIZER_INTERFACE_ATTRIBUTE void __asan_set_death_callback(void (*callback)(void)); SANITIZER_INTERFACE_ATTRIBUTE void __asan_set_error_report_callback(void (*callback)(const char*)); SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE /* OPTIONAL */ void __asan_on_error(); SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats(); SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE /* OPTIONAL */ const char* __asan_default_options(); // 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_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); } // extern "C" #endif // ASAN_INTERFACE_INTERNAL_H Index: projects/clang360-import/contrib/compiler-rt/lib/asan/asan_internal.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/asan_internal.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/asan_internal.h (revision 279194) @@ -1,161 +1,162 @@ //===-- 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" #define ASAN_DEFAULT_FAILURE_EXITCODE 1 #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_WORDSIZE == 32 # 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; struct SignalContext { void *context; uptr addr; uptr pc; uptr sp; uptr bp; SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp) : context(context), addr(addr), pc(pc), sp(sp), bp(bp) { } // Creates signal context in a platform-specific manner. static SignalContext Create(void *siginfo, void *context); }; void AsanInitFromRtl(); // 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(); void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp); void AsanOnSIGSEGV(int, void *siginfo, void *context); +void DisableReexec(); void MaybeReexec(); void ReadContextStack(void *context, uptr *stack, uptr *ssize); void AsanPlatformThreadInit(); 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); // Platform-specific options. #if SANITIZER_MAC bool PlatformHasDifferentMemcpyAndMemmove(); # define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \ (PlatformHasDifferentMemcpyAndMemmove()) #else # define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true #endif // SANITIZER_MAC // Add convenient macro for interface functions that may be represented as // weak hooks. #define ASAN_MALLOC_HOOK(ptr, size) \ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size) #define ASAN_FREE_HOOK(ptr) \ if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr) #define ASAN_ON_ERROR() \ if (&__asan_on_error) __asan_on_error() extern int asan_inited; // Used to avoid infinite recursion in __asan_init(). extern bool asan_init_is_running; extern void (*death_callback)(void); // These magic values are written to shadow for better error reporting. const int kAsanHeapLeftRedzoneMagic = 0xfa; const int kAsanHeapRightRedzoneMagic = 0xfb; const int kAsanHeapFreeMagic = 0xfd; const int kAsanStackLeftRedzoneMagic = 0xf1; const int kAsanStackMidRedzoneMagic = 0xf2; const int kAsanStackRightRedzoneMagic = 0xf3; const int kAsanStackPartialRedzoneMagic = 0xf4; const int kAsanStackAfterReturnMagic = 0xf5; const int kAsanInitializationOrderMagic = 0xf6; const int kAsanUserPoisonedMemoryMagic = 0xf7; const int kAsanContiguousContainerOOBMagic = 0xfc; const int kAsanStackUseAfterScopeMagic = 0xf8; const int kAsanGlobalRedzoneMagic = 0xf9; const int kAsanInternalHeapMagic = 0xfe; const int kAsanArrayCookieMagic = 0xac; const int kAsanIntraObjectRedzone = 0xbb; const int kAsanAllocaLeftMagic = 0xca; const int kAsanAllocaRightMagic = 0xcb; static const uptr kCurrentStackFrameMagic = 0x41B58AB3; static const uptr kRetiredStackFrameMagic = 0x45E0360E; } // namespace __asan #endif // ASAN_INTERNAL_H Index: projects/clang360-import/contrib/compiler-rt/lib/asan/asan_linux.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/asan_linux.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/asan_linux.cc (revision 279194) @@ -1,245 +1,249 @@ //===-- 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 DisableReexec() { + // No need to re-exec on Linux. +} + void MaybeReexec() { // No need to re-exec on Linux. } void *AsanDoesNotSupportStaticLinkage() { // This will fail to link with -static. return &_DYNAMIC; // defined in link.h } #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() { // Ensure that dynamic RT is the first DSO in the list const char *first_dso_name = 0; 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(0, 0, 0, filename, sizeof(filename), 0)) { 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 void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { #if defined(__arm__) ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.arm_pc; *bp = ucontext->uc_mcontext.arm_fp; *sp = ucontext->uc_mcontext.arm_sp; #elif defined(__aarch64__) ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.pc; *bp = ucontext->uc_mcontext.regs[29]; *sp = ucontext->uc_mcontext.sp; #elif defined(__hppa__) ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.sc_iaoq[0]; /* GCC uses %r3 whenever a frame pointer is needed. */ *bp = ucontext->uc_mcontext.sc_gr[3]; *sp = ucontext->uc_mcontext.sc_gr[30]; #elif defined(__x86_64__) # if SANITIZER_FREEBSD ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.mc_rip; *bp = ucontext->uc_mcontext.mc_rbp; *sp = ucontext->uc_mcontext.mc_rsp; # else ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.gregs[REG_RIP]; *bp = ucontext->uc_mcontext.gregs[REG_RBP]; *sp = ucontext->uc_mcontext.gregs[REG_RSP]; # endif #elif defined(__i386__) # if SANITIZER_FREEBSD ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.mc_eip; *bp = ucontext->uc_mcontext.mc_ebp; *sp = ucontext->uc_mcontext.mc_esp; # else ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.gregs[REG_EIP]; *bp = ucontext->uc_mcontext.gregs[REG_EBP]; *sp = ucontext->uc_mcontext.gregs[REG_ESP]; # endif #elif defined(__powerpc__) || defined(__powerpc64__) ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.regs->nip; *sp = ucontext->uc_mcontext.regs->gpr[PT_R1]; // The powerpc{,64}-linux ABIs do not specify r31 as the frame // pointer, but GCC always uses r31 when we need a frame pointer. *bp = ucontext->uc_mcontext.regs->gpr[PT_R31]; #elif defined(__sparc__) ucontext_t *ucontext = (ucontext_t*)context; uptr *stk_ptr; # if defined (__arch64__) *pc = ucontext->uc_mcontext.mc_gregs[MC_PC]; *sp = ucontext->uc_mcontext.mc_gregs[MC_O6]; stk_ptr = (uptr *) (*sp + 2047); *bp = stk_ptr[15]; # else *pc = ucontext->uc_mcontext.gregs[REG_PC]; *sp = ucontext->uc_mcontext.gregs[REG_O6]; stk_ptr = (uptr *) *sp; *bp = stk_ptr[15]; # endif #elif defined(__mips__) ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.gregs[31]; *bp = ucontext->uc_mcontext.gregs[30]; *sp = ucontext->uc_mcontext.gregs[29]; #else # error "Unsupported arch" #endif } void AsanPlatformThreadInit() { // Nothing here for now. } #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/clang360-import/contrib/compiler-rt/lib/asan/asan_mac.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/asan_mac.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/asan_mac.cc (revision 279194) @@ -1,428 +1,436 @@ //===-- 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 // for _NSGetArgv #include // for dladdr() #include #include #include #include #include #include #include #include #include // for free() #include #include namespace __asan { void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { ucontext_t *ucontext = (ucontext_t*)context; # if SANITIZER_WORDSIZE == 64 *pc = ucontext->uc_mcontext->__ss.__rip; *bp = ucontext->uc_mcontext->__ss.__rbp; *sp = ucontext->uc_mcontext->__ss.__rsp; # else *pc = ucontext->uc_mcontext->__ss.__eip; *bp = ucontext->uc_mcontext->__ss.__ebp; *sp = ucontext->uc_mcontext->__ss.__esp; # endif // SANITIZER_WORDSIZE } bool PlatformHasDifferentMemcpyAndMemmove() { // On OS X 10.7 memcpy() and memmove() are both resolved // into memmove$VARIANT$sse42. // See also http://code.google.com/p/address-sanitizer/issues/detail?id=34. // TODO(glider): need to check dynamically that memcpy() and memmove() are // actually the same function. return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD; } extern "C" void __asan_init(); static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES"; LowLevelAllocator allocator_for_env; // Change the value of the env var |name|, leaking the original value. // If |name_value| is NULL, the variable is deleted from the environment, // otherwise the corresponding "NAME=value" string is replaced with // |name_value|. void LeakyResetEnv(const char *name, const char *name_value) { char ***env_ptr = _NSGetEnviron(); CHECK(env_ptr); char **environ = *env_ptr; CHECK(environ); uptr name_len = internal_strlen(name); while (*environ != 0) { uptr len = internal_strlen(*environ); if (len > name_len) { const char *p = *environ; if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') { // Match. if (name_value) { // Replace the old value with the new one. *environ = const_cast(name_value); } else { // Shift the subsequent pointers back. char **del = environ; do { del[0] = del[1]; } while (*del++); } } } environ++; } } +static bool reexec_disabled = false; + +void DisableReexec() { + reexec_disabled = true; +} + void MaybeReexec() { + if (reexec_disabled) return; + // Make sure the dynamic ASan runtime library is preloaded so that the // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec // ourselves. Dl_info info; CHECK(dladdr((void*)((uptr)__asan_init), &info)); char *dyld_insert_libraries = const_cast(GetEnv(kDyldInsertLibraries)); uptr old_env_len = dyld_insert_libraries ? internal_strlen(dyld_insert_libraries) : 0; uptr fname_len = internal_strlen(info.dli_fname); const char *dylib_name = StripModuleName(info.dli_fname); uptr dylib_name_len = internal_strlen(dylib_name); if (!dyld_insert_libraries || !REAL(strstr)(dyld_insert_libraries, dylib_name)) { // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime // library. char program_name[1024]; uint32_t buf_size = sizeof(program_name); _NSGetExecutablePath(program_name, &buf_size); char *new_env = const_cast(info.dli_fname); if (dyld_insert_libraries) { // Append the runtime dylib name to the existing value of // DYLD_INSERT_LIBRARIES. new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2); internal_strncpy(new_env, dyld_insert_libraries, old_env_len); new_env[old_env_len] = ':'; // Copy fname_len and add a trailing zero. internal_strncpy(new_env + old_env_len + 1, info.dli_fname, fname_len + 1); // Ok to use setenv() since the wrappers don't depend on the value of // asan_inited. setenv(kDyldInsertLibraries, new_env, /*overwrite*/1); } else { // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name. setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0); } VReport(1, "exec()-ing the program with\n"); VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env); VReport(1, "to enable ASan wrappers.\n"); execv(program_name, *_NSGetArgv()); // We get here only if execv() failed. Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, " "which is required for ASan to work. ASan tried to set the " "environment variable and re-execute itself, but execv() failed, " "possibly because of sandbox restrictions. Make sure to launch the " "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env); CHECK("execv failed" && 0); } // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove // the dylib from the environment variable, because interceptors are installed // and we don't want our children to inherit the variable. uptr env_name_len = internal_strlen(kDyldInsertLibraries); // Allocate memory to hold the previous env var name, its value, the '=' // sign and the '\0' char. char *new_env = (char*)allocator_for_env.Allocate( old_env_len + 2 + env_name_len); CHECK(new_env); internal_memset(new_env, '\0', old_env_len + 2 + env_name_len); internal_strncpy(new_env, kDyldInsertLibraries, env_name_len); new_env[env_name_len] = '='; char *new_env_pos = new_env + env_name_len + 1; // Iterate over colon-separated pieces of |dyld_insert_libraries|. char *piece_start = dyld_insert_libraries; char *piece_end = NULL; char *old_env_end = dyld_insert_libraries + old_env_len; do { if (piece_start[0] == ':') piece_start++; piece_end = REAL(strchr)(piece_start, ':'); if (!piece_end) piece_end = dyld_insert_libraries + old_env_len; if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break; uptr piece_len = piece_end - piece_start; char *filename_start = (char *)internal_memrchr(piece_start, '/', piece_len); uptr filename_len = piece_len; if (filename_start) { filename_start += 1; filename_len = piece_len - (filename_start - piece_start); } else { filename_start = piece_start; } // If the current piece isn't the runtime library name, // append it to new_env. if ((dylib_name_len != filename_len) || (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) { if (new_env_pos != new_env + env_name_len + 1) { new_env_pos[0] = ':'; new_env_pos++; } internal_strncpy(new_env_pos, piece_start, piece_len); new_env_pos += piece_len; } // Move on to the next piece. piece_start = piece_end; } while (piece_start < old_env_end); // Can't use setenv() here, because it requires the allocator to be // initialized. // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in // a separate function called after InitializeAllocator(). if (new_env_pos == new_env + env_name_len + 1) new_env = NULL; LeakyResetEnv(kDyldInsertLibraries, new_env); } // 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 AsanPlatformThreadInit() { } void ReadContextStack(void *context, uptr *stack, uptr *ssize) { UNIMPLEMENTED(); } // Support for the following functions from libdispatch on Mac OS: // dispatch_async_f() // dispatch_async() // dispatch_sync_f() // dispatch_sync() // dispatch_after_f() // dispatch_after() // dispatch_group_async_f() // dispatch_group_async() // TODO(glider): libdispatch API contains other functions that we don't support // yet. // // dispatch_sync() and dispatch_sync_f() are synchronous, although chances are // they can cause jobs to run on a thread different from the current one. // TODO(glider): if so, we need a test for this (otherwise we should remove // them). // // The following functions use dispatch_barrier_async_f() (which isn't a library // function but is exported) and are thus supported: // dispatch_source_set_cancel_handler_f() // dispatch_source_set_cancel_handler() // dispatch_source_set_event_handler_f() // dispatch_source_set_event_handler() // // The reference manual for Grand Central Dispatch is available at // http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html // The implementation details are at // http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c typedef void* dispatch_group_t; typedef void* dispatch_queue_t; typedef void* dispatch_source_t; typedef u64 dispatch_time_t; typedef void (*dispatch_function_t)(void *block); typedef void* (*worker_t)(void *block); // A wrapper for the ObjC blocks used to support libdispatch. typedef struct { void *block; dispatch_function_t func; u32 parent_tid; } asan_block_context_t; ALWAYS_INLINE void asan_register_worker_thread(int parent_tid, StackTrace *stack) { AsanThread *t = GetCurrentThread(); if (!t) { t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr, parent_tid, stack, /* detached */ true); t->Init(); asanThreadRegistry().StartThread(t->tid(), 0, 0); SetCurrentThread(t); } } // For use by only those functions that allocated the context via // alloc_asan_context(). extern "C" void asan_dispatch_call_block_and_release(void *block) { GET_STACK_TRACE_THREAD; asan_block_context_t *context = (asan_block_context_t*)block; VReport(2, "asan_dispatch_call_block_and_release(): " "context: %p, pthread_self: %p\n", block, pthread_self()); asan_register_worker_thread(context->parent_tid, &stack); // Call the original dispatcher for the block. context->func(context->block); asan_free(context, &stack, FROM_MALLOC); } } // namespace __asan using namespace __asan; // NOLINT // Wrap |ctxt| and |func| into an asan_block_context_t. // The caller retains control of the allocated context. extern "C" asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func, BufferedStackTrace *stack) { asan_block_context_t *asan_ctxt = (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack); asan_ctxt->block = ctxt; asan_ctxt->func = func; asan_ctxt->parent_tid = GetCurrentTidOrInvalid(); return asan_ctxt; } // Define interceptor for dispatch_*_f function with the three most common // parameters: dispatch_queue_t, context, dispatch_function_t. #define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \ INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \ dispatch_function_t func) { \ GET_STACK_TRACE_THREAD; \ asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \ if (Verbosity() >= 2) { \ Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \ asan_ctxt, pthread_self()); \ PRINT_CURRENT_STACK(); \ } \ return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \ asan_dispatch_call_block_and_release); \ } INTERCEPT_DISPATCH_X_F_3(dispatch_async_f) INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f) INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f) INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, dispatch_queue_t dq, void *ctxt, dispatch_function_t func) { GET_STACK_TRACE_THREAD; asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); if (Verbosity() >= 2) { Report("dispatch_after_f: %p\n", asan_ctxt); PRINT_CURRENT_STACK(); } return REAL(dispatch_after_f)(when, dq, (void*)asan_ctxt, asan_dispatch_call_block_and_release); } INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, dispatch_queue_t dq, void *ctxt, dispatch_function_t func) { GET_STACK_TRACE_THREAD; asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); if (Verbosity() >= 2) { Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n", asan_ctxt, pthread_self()); PRINT_CURRENT_STACK(); } REAL(dispatch_group_async_f)(group, dq, (void*)asan_ctxt, asan_dispatch_call_block_and_release); } #if !defined(MISSING_BLOCKS_SUPPORT) extern "C" { void dispatch_async(dispatch_queue_t dq, void(^work)(void)); void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)); void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)); void dispatch_source_set_cancel_handler(dispatch_source_t ds, void(^work)(void)); void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void)); } #define GET_ASAN_BLOCK(work) \ void (^asan_block)(void); \ int parent_tid = GetCurrentTidOrInvalid(); \ asan_block = ^(void) { \ GET_STACK_TRACE_THREAD; \ asan_register_worker_thread(parent_tid, &stack); \ work(); \ } INTERCEPTOR(void, dispatch_async, dispatch_queue_t dq, void(^work)(void)) { ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_async)(dq, asan_block); } INTERCEPTOR(void, dispatch_group_async, dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) { ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_group_async)(dg, dq, asan_block); } INTERCEPTOR(void, dispatch_after, dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) { ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_after)(when, queue, asan_block); } INTERCEPTOR(void, dispatch_source_set_cancel_handler, dispatch_source_t ds, void(^work)(void)) { if (!work) { REAL(dispatch_source_set_cancel_handler)(ds, work); return; } ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_source_set_cancel_handler)(ds, asan_block); } INTERCEPTOR(void, dispatch_source_set_event_handler, dispatch_source_t ds, void(^work)(void)) { ENABLE_FRAME_POINTER; GET_ASAN_BLOCK(work); REAL(dispatch_source_set_event_handler)(ds, asan_block); } #endif #endif // SANITIZER_MAC Index: projects/clang360-import/contrib/compiler-rt/lib/asan/asan_rtl.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/asan_rtl.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/asan_rtl.cc (revision 279194) @@ -1,523 +1,523 @@ //===-- asan_rtl.cc -------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // Main file of the ASan run-time library. //===----------------------------------------------------------------------===// #include "asan_activation.h" #include "asan_allocator.h" #include "asan_interceptors.h" #include "asan_interface_internal.h" #include "asan_internal.h" #include "asan_mapping.h" #include "asan_poisoning.h" #include "asan_report.h" #include "asan_stack.h" #include "asan_stats.h" #include "asan_suppressions.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_symbolizer.h" #include "lsan/lsan_common.h" int __asan_option_detect_stack_use_after_return; // Global interface symbol. uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan. namespace __asan { uptr AsanMappingProfile[kAsanMappingProfileSize]; static void AsanDie() { static atomic_uint32_t num_calls; if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) { // Don't die twice - run a busy loop. while (1) { } } if (flags()->sleep_before_dying) { Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying); SleepForSeconds(flags()->sleep_before_dying); } if (flags()->unmap_shadow_on_exit) { if (kMidMemBeg) { UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg); UnmapOrDie((void*)kMidMemEnd, kHighShadowEnd - kMidMemEnd); } else { UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); } } if (common_flags()->coverage) __sanitizer_cov_dump(); if (flags()->abort_on_error) Abort(); internal__exit(flags()->exitcode); } static void AsanCheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2) { Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file, line, cond, (uptr)v1, (uptr)v2); // FIXME: check for infinite recursion without a thread-local counter here. PRINT_CURRENT_STACK_CHECK(); Die(); } // -------------------------- Globals --------------------- {{{1 int asan_inited; bool asan_init_is_running; #if !ASAN_FIXED_MAPPING uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; #endif // -------------------------- Misc ---------------- {{{1 void ShowStatsAndAbort() { __asan_print_accumulated_stats(); Die(); } // ---------------------- mmap -------------------- {{{1 // Reserve memory range [beg, end]. // We need to use inclusive range because end+1 may not be representable. void ReserveShadowMemoryRange(uptr beg, uptr end) { CHECK_EQ((beg % GetPageSizeCached()), 0); CHECK_EQ(((end + 1) % GetPageSizeCached()), 0); uptr size = end - beg + 1; DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. void *res = MmapFixedNoReserve(beg, size); if (res != (void*)beg) { Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " "Perhaps you're using ulimit -v\n", size); Abort(); } if (common_flags()->no_huge_pages_for_shadow) NoHugePagesInRegion(beg, size); if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size); } // --------------- LowLevelAllocateCallbac ---------- {{{1 static void OnLowLevelAllocate(uptr ptr, uptr size) { PoisonShadow(ptr, size, kAsanInternalHeapMagic); } // -------------------------- Run-time entry ------------------- {{{1 // exported functions #define ASAN_REPORT_ERROR(type, is_write, size) \ extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_report_ ## type ## size(uptr addr); \ void __asan_report_ ## type ## size(uptr addr) { \ GET_CALLER_PC_BP_SP; \ __asan_report_error(pc, bp, sp, addr, is_write, size); \ } ASAN_REPORT_ERROR(load, false, 1) ASAN_REPORT_ERROR(load, false, 2) ASAN_REPORT_ERROR(load, false, 4) ASAN_REPORT_ERROR(load, false, 8) ASAN_REPORT_ERROR(load, false, 16) ASAN_REPORT_ERROR(store, true, 1) ASAN_REPORT_ERROR(store, true, 2) ASAN_REPORT_ERROR(store, true, 4) ASAN_REPORT_ERROR(store, true, 8) ASAN_REPORT_ERROR(store, true, 16) #define ASAN_REPORT_ERROR_N(type, is_write) \ extern "C" NOINLINE INTERFACE_ATTRIBUTE \ void __asan_report_ ## type ## _n(uptr addr, uptr size); \ void __asan_report_ ## type ## _n(uptr addr, uptr size) { \ GET_CALLER_PC_BP_SP; \ __asan_report_error(pc, bp, sp, addr, is_write, size); \ } ASAN_REPORT_ERROR_N(load, false) ASAN_REPORT_ERROR_N(store, true) #define ASAN_MEMORY_ACCESS_CALLBACK(type, is_write, size) \ extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_##type##size(uptr addr); \ void __asan_##type##size(uptr addr) { \ uptr sp = MEM_TO_SHADOW(addr); \ uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast(sp) \ : *reinterpret_cast(sp); \ if (UNLIKELY(s)) { \ if (UNLIKELY(size >= SHADOW_GRANULARITY || \ ((s8)((addr & (SHADOW_GRANULARITY - 1)) + size - 1)) >= \ (s8)s)) { \ if (__asan_test_only_reported_buggy_pointer) { \ *__asan_test_only_reported_buggy_pointer = addr; \ } else { \ GET_CALLER_PC_BP_SP; \ __asan_report_error(pc, bp, sp, addr, is_write, size); \ } \ } \ } \ } ASAN_MEMORY_ACCESS_CALLBACK(load, false, 1) ASAN_MEMORY_ACCESS_CALLBACK(load, false, 2) ASAN_MEMORY_ACCESS_CALLBACK(load, false, 4) ASAN_MEMORY_ACCESS_CALLBACK(load, false, 8) ASAN_MEMORY_ACCESS_CALLBACK(load, false, 16) ASAN_MEMORY_ACCESS_CALLBACK(store, true, 1) ASAN_MEMORY_ACCESS_CALLBACK(store, true, 2) ASAN_MEMORY_ACCESS_CALLBACK(store, true, 4) ASAN_MEMORY_ACCESS_CALLBACK(store, true, 8) ASAN_MEMORY_ACCESS_CALLBACK(store, true, 16) extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_loadN(uptr addr, uptr size) { if (__asan_region_is_poisoned(addr, size)) { GET_CALLER_PC_BP_SP; __asan_report_error(pc, bp, sp, addr, false, size); } } extern "C" NOINLINE INTERFACE_ATTRIBUTE void __asan_storeN(uptr addr, uptr size) { if (__asan_region_is_poisoned(addr, size)) { GET_CALLER_PC_BP_SP; __asan_report_error(pc, bp, sp, addr, true, size); } } // Force the linker to keep the symbols for various ASan interface functions. // We want to keep those in the executable in order to let the instrumented // dynamic libraries access the symbol even if it is not used by the executable // itself. This should help if the build system is removing dead code at link // time. static NOINLINE void force_interface_symbols() { volatile int fake_condition = 0; // prevent dead condition elimination. // __asan_report_* functions are noreturn, so we need a switch to prevent // the compiler from removing any of them. switch (fake_condition) { case 1: __asan_report_load1(0); break; case 2: __asan_report_load2(0); break; case 3: __asan_report_load4(0); break; case 4: __asan_report_load8(0); break; case 5: __asan_report_load16(0); break; case 6: __asan_report_store1(0); break; case 7: __asan_report_store2(0); break; case 8: __asan_report_store4(0); break; case 9: __asan_report_store8(0); break; case 10: __asan_report_store16(0); break; case 12: __asan_register_globals(0, 0); break; case 13: __asan_unregister_globals(0, 0); break; case 14: __asan_set_death_callback(0); break; case 15: __asan_set_error_report_callback(0); break; case 16: __asan_handle_no_return(); break; case 17: __asan_address_is_poisoned(0); break; case 25: __asan_poison_memory_region(0, 0); break; case 26: __asan_unpoison_memory_region(0, 0); break; case 27: __asan_set_error_exit_code(0); break; case 30: __asan_before_dynamic_init(0); break; case 31: __asan_after_dynamic_init(); break; case 32: __asan_poison_stack_memory(0, 0); break; case 33: __asan_unpoison_stack_memory(0, 0); break; case 34: __asan_region_is_poisoned(0, 0); break; case 35: __asan_describe_address(0); break; } } static void asan_atexit() { Printf("AddressSanitizer exit stats:\n"); __asan_print_accumulated_stats(); // Print AsanMappingProfile. for (uptr i = 0; i < kAsanMappingProfileSize; i++) { if (AsanMappingProfile[i] == 0) continue; Printf("asan_mapping.h:%zd -- %zd\n", i, AsanMappingProfile[i]); } } static void InitializeHighMemEnd() { #if !ASAN_FIXED_MAPPING kHighMemEnd = GetMaxVirtualAddress(); // Increase kHighMemEnd to make sure it's properly // aligned together with kHighMemBeg: kHighMemEnd |= SHADOW_GRANULARITY * GetPageSizeCached() - 1; #endif // !ASAN_FIXED_MAPPING CHECK_EQ((kHighMemBeg % GetPageSizeCached()), 0); } static void ProtectGap(uptr a, uptr size) { void *res = Mprotect(a, size); if (a == (uptr)res) return; Report("ERROR: Failed to protect the shadow gap. " "ASan cannot proceed correctly. ABORTING.\n"); DumpProcessMap(); Die(); } static void PrintAddressSpaceLayout() { Printf("|| `[%p, %p]` || HighMem ||\n", (void*)kHighMemBeg, (void*)kHighMemEnd); Printf("|| `[%p, %p]` || HighShadow ||\n", (void*)kHighShadowBeg, (void*)kHighShadowEnd); if (kMidMemBeg) { Printf("|| `[%p, %p]` || ShadowGap3 ||\n", (void*)kShadowGap3Beg, (void*)kShadowGap3End); Printf("|| `[%p, %p]` || MidMem ||\n", (void*)kMidMemBeg, (void*)kMidMemEnd); Printf("|| `[%p, %p]` || ShadowGap2 ||\n", (void*)kShadowGap2Beg, (void*)kShadowGap2End); Printf("|| `[%p, %p]` || MidShadow ||\n", (void*)kMidShadowBeg, (void*)kMidShadowEnd); } Printf("|| `[%p, %p]` || ShadowGap ||\n", (void*)kShadowGapBeg, (void*)kShadowGapEnd); if (kLowShadowBeg) { Printf("|| `[%p, %p]` || LowShadow ||\n", (void*)kLowShadowBeg, (void*)kLowShadowEnd); Printf("|| `[%p, %p]` || LowMem ||\n", (void*)kLowMemBeg, (void*)kLowMemEnd); } Printf("MemToShadow(shadow): %p %p %p %p", (void*)MEM_TO_SHADOW(kLowShadowBeg), (void*)MEM_TO_SHADOW(kLowShadowEnd), (void*)MEM_TO_SHADOW(kHighShadowBeg), (void*)MEM_TO_SHADOW(kHighShadowEnd)); if (kMidMemBeg) { Printf(" %p %p", (void*)MEM_TO_SHADOW(kMidShadowBeg), (void*)MEM_TO_SHADOW(kMidShadowEnd)); } Printf("\n"); Printf("redzone=%zu\n", (uptr)flags()->redzone); Printf("max_redzone=%zu\n", (uptr)flags()->max_redzone); Printf("quarantine_size_mb=%zuM\n", (uptr)flags()->quarantine_size_mb); Printf("malloc_context_size=%zu\n", (uptr)common_flags()->malloc_context_size); Printf("SHADOW_SCALE: %zx\n", (uptr)SHADOW_SCALE); Printf("SHADOW_GRANULARITY: %zx\n", (uptr)SHADOW_GRANULARITY); Printf("SHADOW_OFFSET: %zx\n", (uptr)SHADOW_OFFSET); CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7); if (kMidMemBeg) CHECK(kMidShadowBeg > kLowShadowEnd && kMidMemBeg > kMidShadowEnd && kHighShadowBeg > kMidMemEnd); } static void AsanInitInternal() { if (LIKELY(asan_inited)) return; SanitizerToolName = "AddressSanitizer"; CHECK(!asan_init_is_running && "ASan init calls itself!"); asan_init_is_running = true; // Initialize flags. This must be done early, because most of the // initialization steps look at flags(). - InitializeFlags(flags()); + InitializeFlags(); SetCanPoisonMemory(flags()->poison_heap); SetMallocContextSize(common_flags()->malloc_context_size); InitializeHighMemEnd(); // Make sure we are not statically linked. AsanDoesNotSupportStaticLinkage(); // Install tool-specific callbacks in sanitizer_common. SetDieCallback(AsanDie); SetCheckFailedCallback(AsanCheckFailed); SetPrintfAndReportCallback(AppendToErrorMessageBuffer); __sanitizer_set_report_path(common_flags()->log_path); // Enable UAR detection, if required. __asan_option_detect_stack_use_after_return = flags()->detect_stack_use_after_return; // Re-exec ourselves if we need to set additional env or command line args. MaybeReexec(); // Setup internal allocator callback. SetLowLevelAllocateCallback(OnLowLevelAllocate); InitializeAsanInterceptors(); // Enable system log ("adb logcat") on Android. // Doing this before interceptors are initialized crashes in: // AsanInitInternal -> android_log_write -> __interceptor_strcmp AndroidLogInit(); ReplaceSystemMalloc(); uptr shadow_start = kLowShadowBeg; if (kLowShadowBeg) shadow_start -= GetMmapGranularity(); bool full_shadow_is_available = MemoryRangeIsAvailable(shadow_start, kHighShadowEnd); #if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \ !ASAN_FIXED_MAPPING if (!full_shadow_is_available) { kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0; kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0; } #endif if (Verbosity()) PrintAddressSpaceLayout(); DisableCoreDumperIfNecessary(); if (full_shadow_is_available) { // mmap the low shadow plus at least one page at the left. if (kLowShadowBeg) ReserveShadowMemoryRange(shadow_start, kLowShadowEnd); // mmap the high shadow. ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd); // protect the gap. ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); } else if (kMidMemBeg && MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) && MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) { CHECK(kLowShadowBeg != kLowShadowEnd); // mmap the low shadow plus at least one page at the left. ReserveShadowMemoryRange(shadow_start, kLowShadowEnd); // mmap the mid shadow. ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd); // mmap the high shadow. ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd); // protect the gaps. ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1); ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1); } else { Report("Shadow memory range interleaves with an existing memory mapping. " "ASan cannot proceed correctly. ABORTING.\n"); Report("ASan shadow was supposed to be located in the [%p-%p] range.\n", shadow_start, kHighShadowEnd); DumpProcessMap(); Die(); } AsanTSDInit(PlatformTSDDtor); InstallDeadlySignalHandlers(AsanOnSIGSEGV); AllocatorOptions allocator_options; allocator_options.SetFrom(flags(), common_flags()); InitializeAllocator(allocator_options); MaybeStartBackgroudThread(); SetSoftRssLimitExceededCallback(AsanSoftRssLimitExceededCallback); // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited // should be set to 1 prior to initializing the threads. asan_inited = 1; asan_init_is_running = false; if (flags()->atexit) Atexit(asan_atexit); InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); // Now that ASan runtime is (mostly) initialized, deactivate it if // necessary, so that it can be re-activated when requested. if (flags()->start_deactivated) AsanDeactivate(); // interceptors InitTlsSize(); // Create main thread. AsanThread *main_thread = AsanThread::Create( /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0, /* stack */ nullptr, /* detached */ true); CHECK_EQ(0, main_thread->tid()); SetCurrentThread(main_thread); main_thread->ThreadStart(internal_getpid(), /* signal_thread_is_registered */ nullptr); force_interface_symbols(); // no-op. SanitizerInitializeUnwinder(); #if CAN_SANITIZE_LEAKS - __lsan::InitCommonLsan(false); + __lsan::InitCommonLsan(); if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { Atexit(__lsan::DoLeakCheck); } #endif // CAN_SANITIZE_LEAKS InitializeSuppressions(); VReport(1, "AddressSanitizer Init done\n"); } // Initialize as requested from some part of ASan runtime library (interceptors, // allocator, etc). void AsanInitFromRtl() { AsanInitInternal(); } #if ASAN_DYNAMIC // Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable // (and thus normal initializer from .preinit_array haven't run). class AsanInitializer { public: // NOLINT AsanInitializer() { AsanCheckIncompatibleRT(); AsanCheckDynamicRTPrereqs(); AsanInitFromRtl(); } }; static AsanInitializer asan_initializer; #endif // ASAN_DYNAMIC } // namespace __asan // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT int NOINLINE __asan_set_error_exit_code(int exit_code) { int old = flags()->exitcode; flags()->exitcode = exit_code; return old; } void NOINLINE __asan_handle_no_return() { int local_stack; AsanThread *curr_thread = GetCurrentThread(); CHECK(curr_thread); uptr PageSize = GetPageSizeCached(); uptr top = curr_thread->stack_top(); uptr bottom = ((uptr)&local_stack - PageSize) & ~(PageSize-1); static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M if (top - bottom > kMaxExpectedCleanupSize) { static bool reported_warning = false; if (reported_warning) return; reported_warning = true; Report("WARNING: ASan is ignoring requested __asan_handle_no_return: " "stack top: %p; bottom %p; size: %p (%zd)\n" "False positive error reports may follow\n" "For details see " "http://code.google.com/p/address-sanitizer/issues/detail?id=189\n", top, bottom, top - bottom, top - bottom); return; } PoisonShadow(bottom, top - bottom, 0); if (curr_thread->has_fake_stack()) curr_thread->fake_stack()->HandleNoReturn(); } void NOINLINE __asan_set_death_callback(void (*callback)(void)) { SetUserDieCallback(callback); } // Initialize as requested from instrumented application code. // We use this call as a trigger to wake up ASan from deactivated state. void __asan_init() { AsanCheckIncompatibleRT(); AsanActivate(); AsanInitInternal(); } Index: projects/clang360-import/contrib/compiler-rt/lib/asan/asan_suppressions.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/asan_suppressions.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/asan_suppressions.cc (revision 279194) @@ -1,87 +1,93 @@ //===-- 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 { -static bool suppressions_inited = false; +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 *kSuppressionTypes[] = { + kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary}; void InitializeSuppressions() { - CHECK(!suppressions_inited); - SuppressionContext::InitIfNecessary(); - suppressions_inited = true; + CHECK_EQ(nullptr, suppression_ctx); + suppression_ctx = new (suppression_placeholder) // NOLINT + SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); + suppression_ctx->ParseFromFile(flags()->suppressions); } bool IsInterceptorSuppressed(const char *interceptor_name) { - CHECK(suppressions_inited); - SuppressionContext *ctx = SuppressionContext::Get(); + CHECK(suppression_ctx); Suppression *s; // Match "interceptor_name" suppressions. - return ctx->Match(interceptor_name, SuppressionInterceptorName, &s); + return suppression_ctx->Match(interceptor_name, kInterceptorName, &s); } bool HaveStackTraceBasedSuppressions() { - CHECK(suppressions_inited); - SuppressionContext *ctx = SuppressionContext::Get(); - return ctx->HasSuppressionType(SuppressionInterceptorViaFunction) || - ctx->HasSuppressionType(SuppressionInterceptorViaLibrary); + CHECK(suppression_ctx); + return suppression_ctx->HasSuppressionType(kInterceptorViaFunction) || + suppression_ctx->HasSuppressionType(kInterceptorViaLibrary); } bool IsStackTraceSuppressed(const StackTrace *stack) { - CHECK(suppressions_inited); if (!HaveStackTraceBasedSuppressions()) return false; - SuppressionContext *ctx = SuppressionContext::Get(); + 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 (ctx->HasSuppressionType(SuppressionInterceptorViaLibrary)) { + if (suppression_ctx->HasSuppressionType(kInterceptorViaLibrary)) { const char *module_name; uptr module_offset; // Match "interceptor_via_lib" suppressions. if (symbolizer->GetModuleNameAndOffsetForPC(addr, &module_name, &module_offset) && - ctx->Match(module_name, SuppressionInterceptorViaLibrary, &s)) { + suppression_ctx->Match(module_name, kInterceptorViaLibrary, &s)) { return true; } } - if (ctx->HasSuppressionType(SuppressionInterceptorViaFunction)) { + if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) { SymbolizedStack *frames = symbolizer->SymbolizePC(addr); 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 (ctx->Match(function_name, SuppressionInterceptorViaFunction, &s)) { + if (suppression_ctx->Match(function_name, kInterceptorViaFunction, + &s)) { frames->ClearAll(); return true; } } frames->ClearAll(); } } return false; } } // namespace __asan Index: projects/clang360-import/contrib/compiler-rt/lib/asan/asan_win.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/asan_win.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/asan_win.cc (revision 279194) @@ -1,164 +1,168 @@ //===-- 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 #include #include #include #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_report.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mutex.h" extern "C" { SANITIZER_INTERFACE_ATTRIBUTE int __asan_should_detect_stack_use_after_return() { __asan_init(); return __asan_option_detect_stack_use_after_return; } } namespace __asan { // ---------------------- TSD ---------------- {{{1 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 ---------------- {{{1 +void DisableReexec() { + // No need to re-exec on Windows. +} + void MaybeReexec() { // No need to re-exec on Windows. } 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 AsanPlatformThreadInit() { // Nothing here for now. } void ReadContextStack(void *context, uptr *stack, uptr *ssize) { UNIMPLEMENTED(); } void AsanOnSIGSEGV(int, void *siginfo, void *context) { UNIMPLEMENTED(); } static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler; SignalContext SignalContext::Create(void *siginfo, void *context) { EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo; CONTEXT *context_record = (CONTEXT*)context; uptr pc = (uptr)exception_record->ExceptionAddress; #ifdef _WIN64 uptr bp = (uptr)context_record->Rbp; uptr sp = (uptr)context_record->Rsp; #else uptr bp = (uptr)context_record->Ebp; uptr sp = (uptr)context_record->Esp; #endif uptr access_addr = exception_record->ExceptionInformation[1]; return SignalContext(context, access_addr, pc, sp, bp); } static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) { EXCEPTION_RECORD *exception_record = info->ExceptionRecord; CONTEXT *context = info->ContextRecord; if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION || exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) { const char *description = (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) ? "access-violation" : "in-page-error"; SignalContext sig = SignalContext::Create(exception_record, context); ReportSIGSEGV(description, sig); } // FIXME: Handle EXCEPTION_STACK_OVERFLOW here. 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 // Put a pointer to __asan_set_seh_filter at the end of the global list // of C initializers, after the default EH is set by the CRT. #pragma section(".CRT$XIZ", long, read) // NOLINT static __declspec(allocate(".CRT$XIZ")) int (*__intercept_seh)() = __asan_set_seh_filter; #endif } // namespace __asan #endif // _WIN32 Index: projects/clang360-import/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/asan_win_dll_thunk.cc (revision 279194) @@ -1,376 +1,412 @@ //===-- 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://code.google.com/p/address-sanitizer/issues/detail?id=209 for the // details. //===----------------------------------------------------------------------===// // Only compile this code when buidling asan_dll_thunk.lib // Using #ifdef rather than relying on Makefiles etc. // simplifies the build procedure. #ifdef ASAN_DLL_THUNK #include "asan_init_version.h" #include "interception/interception.h" // ---------- Function interception helper functions and macros ----------- {{{1 extern "C" { void *__stdcall GetModuleHandleA(const char *module_name); void *__stdcall GetProcAddress(void *module, const char *proc_name); void abort(); } static void *getRealProcAddressOrDie(const char *name) { void *ret = GetProcAddress(GetModuleHandleA(0), name); if (!ret) abort(); return ret; } // We need to intercept some functions (e.g. ASan interface, memory allocator -- // let's call them "hooks") exported by the DLL thunk and forward the hooks to // the runtime in the main module. // However, we don't want to keep two lists of these hooks. // To avoid that, the list of hooks should be defined using the // INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted // at once by calling INTERCEPT_HOOKS(). // Use macro+template magic to automatically generate the list of hooks. // Each hook at line LINE defines a template class with a static // FunctionInterceptor::Execute() method intercepting the hook. // The default implementation of FunctionInterceptor is to call // the Execute() method corresponding to the previous line. template struct FunctionInterceptor { static void Execute() { FunctionInterceptor::Execute(); } }; // There shouldn't be any hooks with negative definition line number. template<> struct FunctionInterceptor<0> { static void Execute() {} }; #define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \ template<> struct FunctionInterceptor<__LINE__> { \ static void Execute() { \ void *wrapper = getRealProcAddressOrDie(main_function); \ if (!__interception::OverrideFunction((uptr)dll_function, \ (uptr)wrapper, 0)) \ abort(); \ FunctionInterceptor<__LINE__-1>::Execute(); \ } \ }; // Special case of hooks -- ASan own interface functions. Those are only called // after __asan_init, thus an empty implementation is sufficient. #define INTERFACE_FUNCTION(name) \ extern "C" __declspec(noinline) void name() { \ volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf; \ __debugbreak(); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name) // INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE. #define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute // We can't define our own version of strlen etc. because that would lead to // link-time or even type mismatch errors. Instead, we can declare a function // just to be able to get its address. Me may miss the first few calls to the // functions since it can be called before __asan_init, but that would lead to // false negatives in the startup code before user's global initializers, which // isn't a big deal. #define INTERCEPT_LIBRARY_FUNCTION(name) \ extern "C" void name(); \ INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name) // Disable compiler warnings that show up if we declare our own version // of a compiler intrinsic (e.g. strlen). #pragma warning(disable: 4391) #pragma warning(disable: 4392) static void InterceptHooks(); // }}} // ---------- Function wrapping helpers ----------------------------------- {{{1 #define WRAP_V_V(name) \ extern "C" void name() { \ typedef void (*fntype)(); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ fn(); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_V_W(name) \ extern "C" void name(void *arg) { \ typedef void (*fntype)(void *arg); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ fn(arg); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_V_WW(name) \ extern "C" void name(void *arg1, void *arg2) { \ typedef void (*fntype)(void *, void *); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ fn(arg1, arg2); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_V_WWW(name) \ extern "C" void name(void *arg1, void *arg2, void *arg3) { \ typedef void *(*fntype)(void *, void *, void *); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ fn(arg1, arg2, arg3); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_V(name) \ extern "C" void *name() { \ typedef void *(*fntype)(); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_W(name) \ extern "C" void *name(void *arg) { \ typedef void *(*fntype)(void *arg); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WW(name) \ extern "C" void *name(void *arg1, void *arg2) { \ typedef void *(*fntype)(void *, void *); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg1, arg2); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WWW(name) \ extern "C" void *name(void *arg1, void *arg2, void *arg3) { \ typedef void *(*fntype)(void *, void *, void *); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg1, arg2, arg3); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WWWW(name) \ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \ typedef void *(*fntype)(void *, void *, void *, void *); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg1, arg2, arg3, arg4); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WWWWW(name) \ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ void *arg5) { \ typedef void *(*fntype)(void *, void *, void *, void *, void *); \ static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ return fn(arg1, arg2, arg3, arg4, arg5); \ } \ INTERCEPT_WHEN_POSSIBLE(#name, name); #define WRAP_W_WWWWWW(name) \ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ void *arg5, void *arg6) { \ typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \ 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) extern "C" { int __asan_option_detect_stack_use_after_return; // 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_name); fn(); __asan_option_detect_stack_use_after_return = (__asan_should_detect_stack_use_after_return() != 0); InterceptHooks(); } } INTERFACE_FUNCTION(__asan_handle_no_return) 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_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_cov) +INTERFACE_FUNCTION(__sanitizer_cov_dump) +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_with_check) +INTERFACE_FUNCTION(__sanitizer_free_hook) +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_coverage) +INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes) +INTERFACE_FUNCTION(__sanitizer_malloc_hook) +INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file) +INTERFACE_FUNCTION(__sanitizer_print_stack_trace) +INTERFACE_FUNCTION(__sanitizer_ptr_cmp) +INTERFACE_FUNCTION(__sanitizer_ptr_sub) +INTERFACE_FUNCTION(__sanitizer_report_error_summary) +INTERFACE_FUNCTION(__sanitizer_reset_coverage) +INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify) +INTERFACE_FUNCTION(__sanitizer_set_death_callback) +INTERFACE_FUNCTION(__sanitizer_set_report_path) +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) // TODO(timurrrr): Add more interface functions on the as-needed basis. // ----------------- Memory allocation functions --------------------- WRAP_V_W(free) WRAP_V_WW(_free_dbg) WRAP_W_W(malloc) WRAP_W_WWWW(_malloc_dbg) WRAP_W_WW(calloc) WRAP_W_WWWWW(_calloc_dbg) WRAP_W_WWW(_calloc_impl) WRAP_W_WW(realloc) WRAP_W_WWW(_realloc_dbg) WRAP_W_WWW(_recalloc) 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); 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); } INTERCEPT_LIBRARY_FUNCTION(frexp); INTERCEPT_LIBRARY_FUNCTION(longjmp); INTERCEPT_LIBRARY_FUNCTION(memchr); 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(strlen); INTERCEPT_LIBRARY_FUNCTION(strncat); INTERCEPT_LIBRARY_FUNCTION(strncmp); INTERCEPT_LIBRARY_FUNCTION(strncpy); INTERCEPT_LIBRARY_FUNCTION(strnlen); 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(); INTERCEPT_FUNCTION(_except_handler4); } // We want to call __asan_init before C/C++ initializers/constructors are // executed, otherwise functions like memset might be invoked. // For some strange reason, merely linking in asan_preinit.cc doesn't work // as the callback is never called... Is link.exe doing something too smart? // In DLLs, the callbacks are expected to return 0, // otherwise CRT initialization fails. static int call_asan_init() { __asan_init(); return 0; } #pragma section(".CRT$XIB", long, read) // NOLINT __declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init; #endif // ASAN_DLL_THUNK Index: projects/clang360-import/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc (revision 279194) @@ -1,52 +1,119 @@ //===-- asan_win_uar_thunk.cc ---------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of AddressSanitizer, an address sanity checker. // // This file defines things that need to be present in the application modules // to interact with the ASan DLL runtime correctly and can't be implemented // using the default "import library" generated when linking the DLL RTL. // // This includes: // - forwarding the detect_stack_use_after_return runtime option // - installing a custom SEH handler // //===----------------------------------------------------------------------===// // Only compile this code when buidling asan_dynamic_runtime_thunk.lib // Using #ifdef rather than relying on Makefiles etc. // simplifies the build procedure. #ifdef ASAN_DYNAMIC_RUNTIME_THUNK -extern "C" { -__declspec(dllimport) int __asan_set_seh_filter(); -__declspec(dllimport) int __asan_should_detect_stack_use_after_return(); +#include +#include +extern "C" { +//////////////////////////////////////////////////////////////////////////////// // Define a copy of __asan_option_detect_stack_use_after_return that should be // used when linking an MD runtime with a set of object files on Windows. // // The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return', // so normally we would just dllimport it. Unfortunately, the dllimport // attribute adds __imp_ prefix to the symbol name of a variable. // Since in general we don't know if a given TU is going to be used // with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows // just to work around this issue, let's clone the a variable that is // constant after initialization anyways. +__declspec(dllimport) int __asan_should_detect_stack_use_after_return(); int __asan_option_detect_stack_use_after_return = __asan_should_detect_stack_use_after_return(); +} -// Set the ASan-specific SEH handler at the end of CRT initialization of each -// module (see asan_win.cc for the details). +//////////////////////////////////////////////////////////////////////////////// +// For some reason, the MD CRT doesn't call the C/C++ terminators as MT does. +// To work around this, for each DLL we schedule a call to +// UnregisterGlobalsInRange atexit() specifying the address range of the DLL +// image to unregister globals in that range. We don't do the same +// for the main module (.exe) as the asan_globals.cc allocator is destroyed +// by the time UnregisterGlobalsInRange is executed. +// See PR22545 for the details. +namespace __asan { +__declspec(dllimport) +void UnregisterGlobalsInRange(void *beg, void *end); +} + +namespace { +void *this_module_base, *this_module_end; + +void UnregisterGlobals() { + __asan::UnregisterGlobalsInRange(this_module_base, this_module_end); +} + +int ScheduleUnregisterGlobals() { + HMODULE this_module = 0; + // Increments the reference counter of the DLL module, so need to call + // FreeLibrary later. + if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (LPCTSTR)&UnregisterGlobals, &this_module)) + return 1; + + // Skip the main module. + if (this_module == GetModuleHandle(0)) + return 0; + + MODULEINFO mi; + bool success = + GetModuleInformation(GetCurrentProcess(), this_module, &mi, sizeof(mi)); + if (!FreeLibrary(this_module)) + return 2; + if (!success) + return 3; + + this_module_base = mi.lpBaseOfDll; + this_module_end = (char*)mi.lpBaseOfDll + mi.SizeOfImage; + + return atexit(UnregisterGlobals); +} +} // namespace + +/////////////////////////////////////////////////////////////////////////////// +// ASan SEH handling. +extern "C" __declspec(dllimport) int __asan_set_seh_filter(); +static int SetSEHFilter() { return __asan_set_seh_filter(); } + +/////////////////////////////////////////////////////////////////////////////// +// We schedule some work at start-up by placing callbacks to our code to the +// list of CRT C initializers. // +// First, declare sections we'll be using: +#pragma section(".CRT$XID", long, read) // NOLINT +#pragma section(".CRT$XIZ", long, read) // NOLINT + +// We need to call 'atexit(UnregisterGlobals);' after atexit() is initialized +// (.CRT$XIC) but before the C++ constructors (.CRT$XCA). +__declspec(allocate(".CRT$XID")) +static int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals; + +// We need to set the ASan-specific SEH handler at the end of CRT initialization +// of each module (see also asan_win.cc). +// // Unfortunately, putting a pointer to __asan_set_seh_filter into // __asan_intercept_seh gets optimized out, so we have to use an extra function. -static int SetSEHFilter() { return __asan_set_seh_filter(); } -#pragma section(".CRT$XIZ", long, read) // NOLINT -__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter; -} +extern "C" __declspec(allocate(".CRT$XIZ")) +int (*__asan_seh_interceptor)() = SetSEHFilter; + #endif // ASAN_DYNAMIC_RUNTIME_THUNK Index: projects/clang360-import/contrib/compiler-rt/lib/asan/scripts/asan_device_setup =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/scripts/asan_device_setup (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/scripts/asan_device_setup (revision 279194) @@ -1,268 +1,344 @@ #!/bin/bash #===- lib/asan/scripts/asan_device_setup -----------------------------------===# # # The LLVM Compiler Infrastructure # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. # # Prepare Android device to run ASan applications. # #===------------------------------------------------------------------------===# set -e HERE="$(cd "$(dirname "$0")" && pwd)" revert=no extra_options= device= lib= +use_su=0 function usage { echo "usage: $0 [--revert] [--device device-id] [--lib path] [--extra-options options]" echo " --revert: Uninstall ASan from the device." echo " --lib: Path to ASan runtime library." echo " --extra-options: Extra ASAN_OPTIONS." echo " --device: Install to the given device. Use 'adb devices' to find" echo " device-id." + echo " --use-su: Use 'su -c' prefix for every adb command instead of using" + echo " 'adb root' once." echo exit 1 } +function adb_push { + if [ $use_su -eq 0 ]; then + $ADB push "$1" "$2" + else + local FILENAME=$(basename $1) + $ADB push "$1" "/data/local/tmp/$FILENAME" + $ADB shell su -c "rm \\\"$2/$FILENAME\\\"" >&/dev/null + $ADB shell su -c "cat \\\"/data/local/tmp/$FILENAME\\\" > \\\"$2/$FILENAME\\\"" + $ADB shell su -c "rm \\\"/data/local/tmp/$FILENAME\\\"" + fi +} + +function adb_remount { + if [ $use_su -eq 0 ]; then + $ADB remount + else + local STORAGE=`$ADB shell mount | grep /system | cut -d ' ' -f1` + if [ "$STORAGE" != "" ]; then + echo Remounting $STORAGE at /system + $ADB shell su -c "mount -o remount,rw $STORAGE /system" + else + echo Failed to get storage device name for "/system" mount point + fi + fi +} + +function adb_shell { + if [ $use_su -eq 0 ]; then + $ADB shell $@ + else + $ADB shell su -c "$*" + fi +} + +function adb_root { + if [ $use_su -eq 0 ]; then + $ADB root + fi +} + +function adb_wait_for_device { + $ADB wait-for-device +} + +function adb_pull { + if [ $use_su -eq 0 ]; then + $ADB pull "$1" "$2" + else + local FILENAME=$(basename $1) + $ADB shell rm "/data/local/tmp/$FILENAME" >&/dev/null + $ADB shell su -c "[ -f \\\"$1\\\" ] && cat \\\"$1\\\" > \\\"/data/local/tmp/$FILENAME\\\" && chown root.shell \\\"/data/local/tmp/$FILENAME\\\" && chmod 755 \\\"/data/local/tmp/$FILENAME\\\"" && + $ADB pull "/data/local/tmp/$FILENAME" "$2" >&/dev/null && $ADB shell "rm \"/data/local/tmp/$FILENAME\"" + fi +} + function get_device_arch { # OUTVAR local _outvar=$1 - local _ABI=$($ADB shell getprop ro.product.cpu.abi) + local _ABI=$(adb_shell getprop ro.product.cpu.abi) local _ARCH= if [[ $_ABI == x86* ]]; then _ARCH=i686 elif [[ $_ABI == armeabi* ]]; then _ARCH=arm else echo "Unrecognized device ABI: $_ABI" exit 1 fi eval $_outvar=\$_ARCH } while [[ $# > 0 ]]; do case $1 in --revert) revert=yes ;; --extra-options) shift if [[ $# == 0 ]]; then echo "--extra-options requires an argument." exit 1 fi extra_options="$1" ;; --lib) shift if [[ $# == 0 ]]; then echo "--lib requires an argument." exit 1 fi lib="$1" ;; --device) shift if [[ $# == 0 ]]; then echo "--device requires an argument." exit 1 fi device="$1" ;; + --use-su) + use_su=1 + ;; *) usage ;; esac shift done ADB=${ADB:-adb} if [[ x$device != x ]]; then ADB="$ADB -s $device" fi +if [ $use_su -eq 1 ]; then + # Test if 'su' is present on the device + SU_TEST_OUT=`$ADB shell su -c "echo foo" 2>&1 | sed 's/\r$//'` + if [ $? != 0 -o "$SU_TEST_OUT" != "foo" ]; then + echo "ERROR: Cannot use 'su -c':" + echo "$ adb shell su -c \"echo foo\"" + echo $SU_TEST_OUT + echo "Check that 'su' binary is correctly installed on the device or omit" + echo " --use-su flag" + exit 1 + fi +fi + echo '>> Remounting /system rw' -$ADB wait-for-device -$ADB root -$ADB wait-for-device -$ADB remount -$ADB wait-for-device +adb_wait_for_device +adb_root +adb_wait_for_device +adb_remount +adb_wait_for_device get_device_arch ARCH echo "Target architecture: $ARCH" ASAN_RT="libclang_rt.asan-$ARCH-android.so" if [[ x$revert == xyes ]]; then echo '>> Uninstalling ASan' - if ! $ADB shell readlink /system/bin/app_process | grep 'app_process' >&/dev/null; then + if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then echo '>> Pre-L device detected.' - $ADB shell mv /system/bin/app_process.real /system/bin/app_process - $ADB shell rm /system/bin/asanwrapper - $ADB shell rm /system/lib/$ASAN_RT + adb_shell mv /system/bin/app_process.real /system/bin/app_process + adb_shell rm /system/bin/asanwrapper else - $ADB shell rm /system/bin/app_process.wrap - $ADB shell rm /system/bin/asanwrapper - $ADB shell rm /system/lib/$ASAN_RT - $ADB shell rm /system/bin/app_process - $ADB shell ln -s /system/bin/app_process32 /system/bin/app_process + adb_shell rm /system/bin/app_process.wrap + adb_shell rm /system/bin/asanwrapper + adb_shell rm /system/bin/app_process + adb_shell ln -s /system/bin/app_process32 /system/bin/app_process fi echo '>> Restarting shell' - $ADB shell stop - $ADB shell start + adb_shell stop + adb_shell start + # Remove the library on the last step to give a chance to the 'su' binary to + # be executed without problem. + adb_shell rm /system/lib/$ASAN_RT + echo '>> Done' exit 0 fi if [[ -d "$lib" ]]; then ASAN_RT_PATH="$lib" elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then ASAN_RT_PATH=$(dirname "$lib") elif [[ -f "$HERE/$ASAN_RT" ]]; then ASAN_RT_PATH="$HERE" elif [[ $(basename "$HERE") == "bin" ]]; then # We could be in the toolchain's base directory. # Consider ../lib, ../lib/asan, ../lib/linux and ../lib/clang/$VERSION/lib/linux. P=$(ls "$HERE"/../lib/"$ASAN_RT" "$HERE"/../lib/asan/"$ASAN_RT" "$HERE"/../lib/linux/"$ASAN_RT" "$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1) if [[ -n "$P" ]]; then ASAN_RT_PATH="$(dirname "$P")" fi fi if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then echo ">> ASan runtime library not found" exit 1 fi TMPDIRBASE=$(mktemp -d) TMPDIROLD="$TMPDIRBASE/old" TMPDIR="$TMPDIRBASE/new" mkdir "$TMPDIROLD" -RELEASE=$($ADB shell getprop ro.build.version.release) +RELEASE=$(adb_shell getprop ro.build.version.release) PRE_L=0 if echo "$RELEASE" | grep '^4\.' >&/dev/null; then PRE_L=1 fi -if ! $ADB shell readlink /system/bin/app_process | grep 'app_process' >&/dev/null; then +if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then - if $ADB pull /system/bin/app_process.real /dev/null >&/dev/null; then + if adb_pull /system/bin/app_process.real /dev/null >&/dev/null; then echo '>> Old-style ASan installation detected. Reverting.' - $ADB shell mv /system/bin/app_process.real /system/bin/app_process + adb_shell mv /system/bin/app_process.real /system/bin/app_process fi echo '>> Pre-L device detected. Setting up app_process symlink.' - $ADB shell mv /system/bin/app_process /system/bin/app_process32 - $ADB shell ln -s /system/bin/app_process32 /system/bin/app_process + adb_shell mv /system/bin/app_process /system/bin/app_process32 + adb_shell ln -s /system/bin/app_process32 /system/bin/app_process fi echo '>> Copying files from the device' -$ADB pull /system/bin/app_process.wrap "$TMPDIROLD" || true -$ADB pull /system/bin/asanwrapper "$TMPDIROLD" || true -$ADB pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true +adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true +adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true +adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true cp -r "$TMPDIROLD" "$TMPDIR" if [[ -f "$TMPDIR/app_process.wrap" ]]; then echo ">> Previous installation detected" else echo ">> New installation" fi echo '>> Generating wrappers' cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/" # FIXME: alloc_dealloc_mismatch=0 prevents a failure in libdvm startup, # which may or may not be a real bug (probably not). ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0 # On Android-L not allowing user segv handler breaks some applications. if [[ PRE_L -eq 0 ]]; then ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1" fi if [[ x$extra_options != x ]] ; then ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options" fi # Zygote wrapper. cat <"$TMPDIR/app_process.wrap" #!/system/bin/sh-from-zygote ASAN_OPTIONS=$ASAN_OPTIONS \\ LD_PRELOAD=\$LD_PRELOAD:$ASAN_RT \\ exec /system/bin/app_process32 \$@ EOF # General command-line tool wrapper (use for anything that's not started as # zygote). cat <"$TMPDIR/asanwrapper" #!/system/bin/sh LD_PRELOAD=$ASAN_RT \\ exec \$@ EOF if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then echo '>> Pushing files to the device' - $ADB push "$TMPDIR/$ASAN_RT" /system/lib/ - $ADB push "$TMPDIR/app_process.wrap" /system/bin/app_process.wrap - $ADB push "$TMPDIR/asanwrapper" /system/bin/asanwrapper + adb_push "$TMPDIR/$ASAN_RT" /system/lib/ + adb_push "$TMPDIR/app_process.wrap" /system/bin + adb_push "$TMPDIR/asanwrapper" /system/bin - $ADB shell rm /system/bin/app_process - $ADB shell ln -s /system/bin/app_process.wrap /system/bin/app_process + adb_shell rm /system/bin/app_process + adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process - $ADB shell chown root.shell \ + adb_shell chown root.shell \ /system/lib/"$ASAN_RT" \ /system/bin/app_process.wrap \ /system/bin/asanwrapper - $ADB shell chmod 644 \ + adb_shell chmod 644 \ /system/lib/"$ASAN_RT" - $ADB shell chmod 755 \ + adb_shell chmod 755 \ /system/bin/app_process.wrap \ /system/bin/asanwrapper # Make SELinux happy by keeping app_process wrapper and the shell # it runs on in zygote domain. ENFORCING=0 - if $ADB shell getenforce | grep Enforcing >/dev/null; then + if adb_shell getenforce | grep Enforcing >/dev/null; then # Sometimes shell is not allowed to change file contexts. # Temporarily switch to permissive. ENFORCING=1 - $ADB shell setenforce 0 + adb_shell setenforce 0 fi - $ADB shell cp /system/bin/sh /system/bin/sh-from-zygote + adb_shell cp /system/bin/sh /system/bin/sh-from-zygote if [[ PRE_L -eq 1 ]]; then CTX=u:object_r:system_file:s0 else CTX=u:object_r:zygote_exec:s0 fi - $ADB shell chcon $CTX \ + adb_shell chcon $CTX \ /system/bin/sh-from-zygote \ /system/bin/app_process.wrap \ /system/bin/app_process32 if [ $ENFORCING == 1 ]; then - $ADB shell setenforce 1 + adb_shell setenforce 1 fi echo '>> Restarting shell (asynchronous)' - $ADB shell stop - $ADB shell start + adb_shell stop + adb_shell start echo '>> Please wait until the device restarts' else echo '>> Device is up to date' fi rm -r "$TMPDIRBASE" Index: projects/clang360-import/contrib/compiler-rt/lib/asan/tests/asan_noinst_test.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/asan/tests/asan_noinst_test.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/asan/tests/asan_noinst_test.cc (revision 279194) @@ -1,260 +1,263 @@ //===-- asan_noinst_test.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 test file should be compiled w/o asan instrumentation. //===----------------------------------------------------------------------===// #include "asan_allocator.h" #include "asan_internal.h" #include "asan_mapping.h" #include "asan_test_utils.h" #include #include #include #include #include // for memset() #include #include #include // ATTENTION! // Please don't call intercepted functions (including malloc() and friends) // in this test. The static runtime library is linked explicitly (without // -fsanitize=address), thus the interceptors do not work correctly on OS X. // Make sure __asan_init is called before any test case is run. struct AsanInitCaller { - AsanInitCaller() { __asan_init(); } + AsanInitCaller() { + __asan::DisableReexec(); + __asan_init(); + } }; static AsanInitCaller asan_init_caller; TEST(AddressSanitizer, InternalSimpleDeathTest) { EXPECT_DEATH(exit(1), ""); } static void MallocStress(size_t n) { u32 seed = my_rand(); BufferedStackTrace stack1; stack1.trace_buffer[0] = 0xa123; stack1.trace_buffer[1] = 0xa456; stack1.size = 2; BufferedStackTrace stack2; stack2.trace_buffer[0] = 0xb123; stack2.trace_buffer[1] = 0xb456; stack2.size = 2; BufferedStackTrace stack3; stack3.trace_buffer[0] = 0xc123; stack3.trace_buffer[1] = 0xc456; stack3.size = 2; std::vector vec; for (size_t i = 0; i < n; i++) { if ((i % 3) == 0) { if (vec.empty()) continue; size_t idx = my_rand_r(&seed) % vec.size(); void *ptr = vec[idx]; vec[idx] = vec.back(); vec.pop_back(); __asan::asan_free(ptr, &stack1, __asan::FROM_MALLOC); } else { size_t size = my_rand_r(&seed) % 1000 + 1; switch ((my_rand_r(&seed) % 128)) { case 0: size += 1024; break; case 1: size += 2048; break; case 2: size += 4096; break; } size_t alignment = 1 << (my_rand_r(&seed) % 10 + 1); char *ptr = (char*)__asan::asan_memalign(alignment, size, &stack2, __asan::FROM_MALLOC); EXPECT_EQ(size, __asan::asan_malloc_usable_size(ptr, 0, 0)); vec.push_back(ptr); ptr[0] = 0; ptr[size-1] = 0; ptr[size/2] = 0; } } for (size_t i = 0; i < vec.size(); i++) __asan::asan_free(vec[i], &stack3, __asan::FROM_MALLOC); } TEST(AddressSanitizer, NoInstMallocTest) { MallocStress(ASAN_LOW_MEMORY ? 300000 : 1000000); } TEST(AddressSanitizer, ThreadedMallocStressTest) { const int kNumThreads = 4; const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000; pthread_t t[kNumThreads]; for (int i = 0; i < kNumThreads; i++) { PTHREAD_CREATE(&t[i], 0, (void* (*)(void *x))MallocStress, (void*)kNumIterations); } for (int i = 0; i < kNumThreads; i++) { PTHREAD_JOIN(t[i], 0); } } static void PrintShadow(const char *tag, uptr ptr, size_t size) { fprintf(stderr, "%s shadow: %lx size % 3ld: ", tag, (long)ptr, (long)size); uptr prev_shadow = 0; for (sptr i = -32; i < (sptr)size + 32; i++) { uptr shadow = __asan::MemToShadow(ptr + i); if (i == 0 || i == (sptr)size) fprintf(stderr, "."); if (shadow != prev_shadow) { prev_shadow = shadow; fprintf(stderr, "%02x", (int)*(u8*)shadow); } } fprintf(stderr, "\n"); } TEST(AddressSanitizer, DISABLED_InternalPrintShadow) { for (size_t size = 1; size <= 513; size++) { char *ptr = new char[size]; PrintShadow("m", (uptr)ptr, size); delete [] ptr; PrintShadow("f", (uptr)ptr, size); } } TEST(AddressSanitizer, QuarantineTest) { BufferedStackTrace stack; stack.trace_buffer[0] = 0x890; stack.size = 1; const int size = 1024; void *p = __asan::asan_malloc(size, &stack); __asan::asan_free(p, &stack, __asan::FROM_MALLOC); size_t i; size_t max_i = 1 << 30; for (i = 0; i < max_i; i++) { void *p1 = __asan::asan_malloc(size, &stack); __asan::asan_free(p1, &stack, __asan::FROM_MALLOC); if (p1 == p) break; } EXPECT_GE(i, 10000U); EXPECT_LT(i, max_i); } void *ThreadedQuarantineTestWorker(void *unused) { (void)unused; u32 seed = my_rand(); BufferedStackTrace stack; stack.trace_buffer[0] = 0x890; stack.size = 1; for (size_t i = 0; i < 1000; i++) { void *p = __asan::asan_malloc(1 + (my_rand_r(&seed) % 4000), &stack); __asan::asan_free(p, &stack, __asan::FROM_MALLOC); } return NULL; } // Check that the thread local allocators are flushed when threads are // destroyed. TEST(AddressSanitizer, ThreadedQuarantineTest) { const int n_threads = 3000; size_t mmaped1 = __sanitizer_get_heap_size(); for (int i = 0; i < n_threads; i++) { pthread_t t; PTHREAD_CREATE(&t, NULL, ThreadedQuarantineTestWorker, 0); PTHREAD_JOIN(t, 0); size_t mmaped2 = __sanitizer_get_heap_size(); EXPECT_LT(mmaped2 - mmaped1, 320U * (1 << 20)); } } void *ThreadedOneSizeMallocStress(void *unused) { (void)unused; BufferedStackTrace stack; stack.trace_buffer[0] = 0x890; stack.size = 1; const size_t kNumMallocs = 1000; for (int iter = 0; iter < 1000; iter++) { void *p[kNumMallocs]; for (size_t i = 0; i < kNumMallocs; i++) { p[i] = __asan::asan_malloc(32, &stack); } for (size_t i = 0; i < kNumMallocs; i++) { __asan::asan_free(p[i], &stack, __asan::FROM_MALLOC); } } return NULL; } TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) { const int kNumThreads = 4; pthread_t t[kNumThreads]; for (int i = 0; i < kNumThreads; i++) { PTHREAD_CREATE(&t[i], 0, ThreadedOneSizeMallocStress, 0); } for (int i = 0; i < kNumThreads; i++) { PTHREAD_JOIN(t[i], 0); } } TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) { using __asan::kHighMemEnd; // Check that __asan_region_is_poisoned works for shadow regions. uptr ptr = kLowShadowBeg + 200; EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100)); ptr = kShadowGapBeg + 200; EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100)); ptr = kHighShadowBeg + 200; EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100)); } // Test __asan_load1 & friends. TEST(AddressSanitizer, LoadStoreCallbacks) { typedef void (*CB)(uptr p); CB cb[2][5] = { { __asan_load1, __asan_load2, __asan_load4, __asan_load8, __asan_load16, }, { __asan_store1, __asan_store2, __asan_store4, __asan_store8, __asan_store16, } }; uptr buggy_ptr; __asan_test_only_reported_buggy_pointer = &buggy_ptr; BufferedStackTrace stack; stack.trace_buffer[0] = 0x890; stack.size = 1; for (uptr len = 16; len <= 32; len++) { char *ptr = (char*) __asan::asan_malloc(len, &stack); uptr p = reinterpret_cast(ptr); for (uptr is_write = 0; is_write <= 1; is_write++) { for (uptr size_log = 0; size_log <= 4; size_log++) { uptr size = 1 << size_log; CB call = cb[is_write][size_log]; // Iterate only size-aligned offsets. for (uptr offset = 0; offset <= len; offset += size) { buggy_ptr = 0; call(p + offset); if (offset + size <= len) EXPECT_EQ(buggy_ptr, 0U); else EXPECT_EQ(buggy_ptr, p + offset); } } } __asan::asan_free(ptr, &stack, __asan::FROM_MALLOC); } __asan_test_only_reported_buggy_pointer = 0; } Index: projects/clang360-import/contrib/compiler-rt/lib/builtins/clear_cache.c =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/builtins/clear_cache.c (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/builtins/clear_cache.c (revision 279194) @@ -1,156 +1,156 @@ /* ===-- 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" #if __APPLE__ #include #endif #if defined(__FreeBSD__) && defined(__arm__) #include #include #endif #if defined(__NetBSD__) && defined(__arm__) #include #endif -#if defined(__ANDROID__) && defined(__mips__) +#if defined(__mips__) #include #include - #ifdef __LP64__ + #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(__ANDROID__) && defined(__arm__) #include #endif /* * The compiler generates calls to __clear_cache() when creating * trampoline functions on the stack for use with nested functions. * It is expected to invalidate the instruction cache for the * specified range. */ void __clear_cache(void *start, void *end) { #if __i386__ || __x86_64__ /* * Intel processors have a unified instruction and data cache * so there is nothing to do */ #elif defined(__arm__) && !defined(__APPLE__) #if defined(__FreeBSD__) || defined(__NetBSD__) 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(__ANDROID__) 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) : "r0"); if (start_reg != 0) { compilerrt_abort(); } #else compilerrt_abort(); #endif -#elif defined(__ANDROID__) && defined(__mips__) +#elif defined(__mips__) const uintptr_t start_int = (uintptr_t) start; const uintptr_t end_int = (uintptr_t) end; - #ifdef __LP64__ + #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; // 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 (uint64_t 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 (uint64_t 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/clang360-import/contrib/compiler-rt/lib/dfsan/dfsan.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/dfsan/dfsan.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/dfsan/dfsan.cc (revision 279194) @@ -1,381 +1,380 @@ //===-- dfsan.cc ----------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of DataFlowSanitizer. // // DataFlowSanitizer runtime. This file defines the public interface to // DataFlowSanitizer as well as the definition of certain runtime functions // called automatically by the compiler (specifically the instrumentation pass // in llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp). // // The public interface is defined in include/sanitizer/dfsan_interface.h whose // functions are prefixed dfsan_ while the compiler interface functions are // prefixed __dfsan_. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_libc.h" #include "dfsan/dfsan.h" using namespace __dfsan; typedef atomic_uint16_t atomic_dfsan_label; static const dfsan_label kInitializingLabel = -1; static const uptr kNumLabels = 1 << (sizeof(dfsan_label) * 8); static atomic_dfsan_label __dfsan_last_label; static dfsan_label_info __dfsan_label_info[kNumLabels]; Flags __dfsan::flags_data; SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_retval_tls; SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL dfsan_label __dfsan_arg_tls[64]; // On Linux/x86_64, memory is laid out as follows: // // +--------------------+ 0x800000000000 (top of memory) // | application memory | // +--------------------+ 0x700000008000 (kAppAddr) // | | // | unused | // | | // +--------------------+ 0x200200000000 (kUnusedAddr) // | union table | // +--------------------+ 0x200000000000 (kUnionTableAddr) // | shadow memory | // +--------------------+ 0x000000010000 (kShadowAddr) // | reserved by kernel | // +--------------------+ 0x000000000000 // // To derive a shadow memory address from an application memory address, // bits 44-46 are cleared to bring the address into the range // [0x000000008000,0x100000000000). Then the address is shifted left by 1 to // account for the double byte representation of shadow labels and move the // address into the shadow memory range. See the function shadow_for below. // On Linux/MIPS64, memory is laid out as follows: // // +--------------------+ 0x10000000000 (top of memory) // | application memory | // +--------------------+ 0xF000008000 (kAppAddr) // | | // | unused | // | | // +--------------------+ 0x2200000000 (kUnusedAddr) // | union table | // +--------------------+ 0x2000000000 (kUnionTableAddr) // | shadow memory | // +--------------------+ 0x0000010000 (kShadowAddr) // | reserved by kernel | // +--------------------+ 0x0000000000 typedef atomic_dfsan_label dfsan_union_table_t[kNumLabels][kNumLabels]; #if defined(__x86_64__) static const uptr kShadowAddr = 0x10000; static const uptr kUnionTableAddr = 0x200000000000; static const uptr kUnusedAddr = kUnionTableAddr + sizeof(dfsan_union_table_t); static const uptr kAppAddr = 0x700000008000; #elif defined(__mips64) static const uptr kShadowAddr = 0x10000; static const uptr kUnionTableAddr = 0x2000000000; static const uptr kUnusedAddr = kUnionTableAddr + sizeof(dfsan_union_table_t); static const uptr kAppAddr = 0xF000008000; #else # error "DFSan not supported for this platform!" #endif static atomic_dfsan_label *union_table(dfsan_label l1, dfsan_label l2) { return &(*(dfsan_union_table_t *) kUnionTableAddr)[l1][l2]; } // Checks we do not run out of labels. static void dfsan_check_label(dfsan_label label) { if (label == kInitializingLabel) { Report("FATAL: DataFlowSanitizer: out of labels\n"); Die(); } } // Resolves the union of two unequal labels. Nonequality is a precondition for // this function (the instrumentation pass inlines the equality test). extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label __dfsan_union(dfsan_label l1, dfsan_label l2) { DCHECK_NE(l1, l2); if (l1 == 0) return l2; if (l2 == 0) return l1; if (l1 > l2) Swap(l1, l2); atomic_dfsan_label *table_ent = union_table(l1, l2); // We need to deal with the case where two threads concurrently request // a union of the same pair of labels. If the table entry is uninitialized, // (i.e. 0) use a compare-exchange to set the entry to kInitializingLabel // (i.e. -1) to mark that we are initializing it. dfsan_label label = 0; if (atomic_compare_exchange_strong(table_ent, &label, kInitializingLabel, memory_order_acquire)) { // Check whether l2 subsumes l1. We don't need to check whether l1 // subsumes l2 because we are guaranteed here that l1 < l2, and (at least // in the cases we are interested in) a label may only subsume labels // created earlier (i.e. with a lower numerical value). if (__dfsan_label_info[l2].l1 == l1 || __dfsan_label_info[l2].l2 == l1) { label = l2; } else { label = atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1; dfsan_check_label(label); __dfsan_label_info[label].l1 = l1; __dfsan_label_info[label].l2 = l2; } atomic_store(table_ent, label, memory_order_release); } else if (label == kInitializingLabel) { // Another thread is initializing the entry. Wait until it is finished. do { internal_sched_yield(); label = atomic_load(table_ent, memory_order_acquire); } while (label == kInitializingLabel); } return label; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label __dfsan_union_load(const dfsan_label *ls, uptr n) { dfsan_label label = ls[0]; for (uptr i = 1; i != n; ++i) { dfsan_label next_label = ls[i]; if (label != next_label) label = __dfsan_union(label, next_label); } return label; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_unimplemented(char *fname) { if (flags().warn_unimplemented) Report("WARNING: DataFlowSanitizer: call to uninstrumented function %s\n", fname); } // Use '-mllvm -dfsan-debug-nonzero-labels' and break on this function // to try to figure out where labels are being introduced in a nominally // label-free program. extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_nonzero_label() { if (flags().warn_nonzero_labels) Report("WARNING: DataFlowSanitizer: saw nonzero label\n"); } // Indirect call to an uninstrumented vararg function. We don't have a way of // handling these at the moment. extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_vararg_wrapper(const char *fname) { Report("FATAL: DataFlowSanitizer: unsupported indirect call to vararg " "function %s\n", fname); Die(); } // Like __dfsan_union, but for use from the client or custom functions. Hence // the equality comparison is done here before calling __dfsan_union. SANITIZER_INTERFACE_ATTRIBUTE dfsan_label dfsan_union(dfsan_label l1, dfsan_label l2) { if (l1 == l2) return l1; return __dfsan_union(l1, l2); } extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label dfsan_create_label(const char *desc, void *userdata) { dfsan_label label = atomic_fetch_add(&__dfsan_last_label, 1, memory_order_relaxed) + 1; dfsan_check_label(label); __dfsan_label_info[label].l1 = __dfsan_label_info[label].l2 = 0; __dfsan_label_info[label].desc = desc; __dfsan_label_info[label].userdata = userdata; return label; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_set_label(dfsan_label label, void *addr, uptr size) { for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp) { // Don't write the label if it is already the value we need it to be. // In a program where most addresses are not labeled, it is common that // a page of shadow memory is entirely zeroed. The Linux copy-on-write // implementation will share all of the zeroed pages, making a copy of a // page when any value is written. The un-sharing will happen even if // the value written does not change the value in memory. Avoiding the // write when both |label| and |*labelp| are zero dramatically reduces // the amount of real memory used by large programs. if (label == *labelp) continue; *labelp = label; } } SANITIZER_INTERFACE_ATTRIBUTE void dfsan_set_label(dfsan_label label, void *addr, uptr size) { __dfsan_set_label(label, addr, size); } SANITIZER_INTERFACE_ATTRIBUTE void dfsan_add_label(dfsan_label label, void *addr, uptr size) { for (dfsan_label *labelp = shadow_for(addr); size != 0; --size, ++labelp) if (*labelp != label) *labelp = __dfsan_union(*labelp, label); } // Unlike the other dfsan interface functions the behavior of this function // depends on the label of one of its arguments. Hence it is implemented as a // custom function. extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label __dfsw_dfsan_get_label(long data, dfsan_label data_label, dfsan_label *ret_label) { *ret_label = 0; return data_label; } SANITIZER_INTERFACE_ATTRIBUTE dfsan_label dfsan_read_label(const void *addr, uptr size) { if (size == 0) return 0; return __dfsan_union_load(shadow_for(addr), size); } extern "C" SANITIZER_INTERFACE_ATTRIBUTE const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label) { return &__dfsan_label_info[label]; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE int dfsan_has_label(dfsan_label label, dfsan_label elem) { if (label == elem) return true; const dfsan_label_info *info = dfsan_get_label_info(label); if (info->l1 != 0) { return dfsan_has_label(info->l1, elem) || dfsan_has_label(info->l2, elem); } else { return false; } } extern "C" SANITIZER_INTERFACE_ATTRIBUTE dfsan_label dfsan_has_label_with_desc(dfsan_label label, const char *desc) { const dfsan_label_info *info = dfsan_get_label_info(label); if (info->l1 != 0) { return dfsan_has_label_with_desc(info->l1, desc) || dfsan_has_label_with_desc(info->l2, desc); } else { return internal_strcmp(desc, info->desc) == 0; } } extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr dfsan_get_label_count(void) { dfsan_label max_label_allocated = atomic_load(&__dfsan_last_label, memory_order_relaxed); return static_cast(max_label_allocated); } extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_dump_labels(int fd) { dfsan_label last_label = atomic_load(&__dfsan_last_label, memory_order_relaxed); for (uptr l = 1; l <= last_label; ++l) { char buf[64]; internal_snprintf(buf, sizeof(buf), "%u %u %u ", l, __dfsan_label_info[l].l1, __dfsan_label_info[l].l2); internal_write(fd, buf, internal_strlen(buf)); if (__dfsan_label_info[l].l1 == 0 && __dfsan_label_info[l].desc) { internal_write(fd, __dfsan_label_info[l].desc, internal_strlen(__dfsan_label_info[l].desc)); } internal_write(fd, "\n", 1); } } void Flags::SetDefaults() { #define DFSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; #include "dfsan_flags.inc" #undef DFSAN_FLAG } -void RegisterDfsanFlags(FlagParser *parser, Flags *f) { +static void RegisterDfsanFlags(FlagParser *parser, Flags *f) { #define DFSAN_FLAG(Type, Name, DefaultValue, Description) \ RegisterFlag(parser, #Name, Description, &f->Name); #include "dfsan_flags.inc" #undef DFSAN_FLAG } -static void InitializeFlags(Flags &f, const char *env) { +static void InitializeFlags() { FlagParser parser; - RegisterDfsanFlags(&parser, &f); - f.SetDefaults(); - parser.ParseString(env); + RegisterDfsanFlags(&parser, &flags()); + flags().SetDefaults(); + parser.ParseString(GetEnv("DFSAN_OPTIONS")); } static void dfsan_fini() { if (internal_strcmp(flags().dump_labels_at_exit, "") != 0) { fd_t fd = OpenFile(flags().dump_labels_at_exit, true /* write */); if (fd == kInvalidFd) { Report("WARNING: DataFlowSanitizer: unable to open output file %s\n", flags().dump_labels_at_exit); return; } Report("INFO: DataFlowSanitizer: dumping labels to %s\n", flags().dump_labels_at_exit); dfsan_dump_labels(fd); internal_close(fd); } } #ifdef DFSAN_NOLIBC extern "C" void dfsan_init() { #else static void dfsan_init(int argc, char **argv, char **envp) { #endif MmapFixedNoReserve(kShadowAddr, kUnusedAddr - kShadowAddr); // Protect the region of memory we don't use, to preserve the one-to-one // mapping from application to shadow memory. But if ASLR is disabled, Linux // will load our executable in the middle of our unused region. This mostly // works so long as the program doesn't use too much memory. We support this // case by disabling memory protection when ASLR is disabled. uptr init_addr = (uptr)&dfsan_init; if (!(init_addr >= kUnusedAddr && init_addr < kAppAddr)) Mprotect(kUnusedAddr, kAppAddr - kUnusedAddr); - InitializeFlags(flags(), GetEnv("DFSAN_OPTIONS")); - + InitializeFlags(); InitializeInterceptors(); // Register the fini callback to run when the program terminates successfully // or it is killed by the runtime. Atexit(dfsan_fini); SetDieCallback(dfsan_fini); __dfsan_label_info[kInitializingLabel].desc = ""; } #if !defined(DFSAN_NOLIBC) && SANITIZER_CAN_USE_PREINIT_ARRAY __attribute__((section(".preinit_array"), used)) static void (*dfsan_init_ptr)(int, char **, char **) = dfsan_init; #endif Index: projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan.cc (revision 279194) @@ -1,66 +1,96 @@ //=-- lsan.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 LeakSanitizer. // Standalone LSan RTL. // //===----------------------------------------------------------------------===// #include "lsan.h" #include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "lsan_allocator.h" #include "lsan_common.h" #include "lsan_thread.h" bool lsan_inited; bool lsan_init_is_running; namespace __lsan { ///// Interface to the common LSan module. ///// bool WordIsPoisoned(uptr addr) { return false; } } // namespace __lsan using namespace __lsan; // NOLINT +static void InitializeFlags() { + // Set all the default values. + SetCommonFlagsDefaults(); + { + CommonFlags cf; + cf.CopyFrom(*common_flags()); + cf.external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH"); + cf.malloc_context_size = 30; + cf.detect_leaks = true; + OverrideCommonFlags(cf); + } + + Flags *f = flags(); + f->SetDefaults(); + + FlagParser parser; + RegisterLsanFlags(&parser, f); + RegisterCommonFlags(&parser); + + parser.ParseString(GetEnv("LSAN_OPTIONS")); + + SetVerbosity(common_flags()->verbosity); + + if (Verbosity()) ReportUnrecognizedFlags(); + + if (common_flags()->help) parser.PrintFlagDescriptions(); +} + extern "C" void __lsan_init() { CHECK(!lsan_init_is_running); if (lsan_inited) return; lsan_init_is_running = true; SanitizerToolName = "LeakSanitizer"; - InitCommonLsan(true); + InitializeFlags(); + InitCommonLsan(); InitializeAllocator(); InitTlsSize(); InitializeInterceptors(); InitializeThreadRegistry(); u32 tid = ThreadCreate(0, 0, true); CHECK_EQ(tid, 0); ThreadStart(tid, GetTid()); SetCurrentThread(tid); if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) Atexit(DoLeakCheck); InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); lsan_inited = true; lsan_init_is_running = false; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_print_stack_trace() { GET_STACK_TRACE_FATAL; stack.Print(); } Index: projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan_allocator.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan_allocator.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan_allocator.cc (revision 279194) @@ -1,240 +1,250 @@ //=-- lsan_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 LeakSanitizer. // See lsan_allocator.h for details. // //===----------------------------------------------------------------------===// #include "lsan_allocator.h" #include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "lsan_common.h" extern "C" void *memset(void *ptr, int value, uptr num); namespace __lsan { -static const uptr kMaxAllowedMallocSize = 8UL << 30; -static const uptr kAllocatorSpace = 0x600000000000ULL; -static const uptr kAllocatorSize = 0x40000000000ULL; // 4T. - struct ChunkMetadata { bool allocated : 8; // Must be first. ChunkTag tag : 2; uptr requested_size : 54; u32 stack_trace_id; }; +#if defined(__mips64) +static const uptr kMaxAllowedMallocSize = 4UL << 30; +static const uptr kRegionSizeLog = 20; +static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; +typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap; +typedef CompactSizeClassMap SizeClassMap; +typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, + sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap> + PrimaryAllocator; +#else +static const uptr kMaxAllowedMallocSize = 8UL << 30; +static const uptr kAllocatorSpace = 0x600000000000ULL; +static const uptr kAllocatorSize = 0x40000000000ULL; // 4T. typedef SizeClassAllocator64 PrimaryAllocator; +#endif typedef SizeClassAllocatorLocalCache AllocatorCache; typedef LargeMmapAllocator<> SecondaryAllocator; typedef CombinedAllocator Allocator; static Allocator allocator; static THREADLOCAL AllocatorCache cache; void InitializeAllocator() { allocator.InitLinkerInitialized(common_flags()->allocator_may_return_null); } void AllocatorThreadFinish() { allocator.SwallowCache(&cache); } static ChunkMetadata *Metadata(const void *p) { return reinterpret_cast(allocator.GetMetaData(p)); } static void RegisterAllocation(const StackTrace &stack, void *p, uptr size) { if (!p) return; ChunkMetadata *m = Metadata(p); CHECK(m); m->tag = DisabledInThisThread() ? kIgnored : kDirectlyLeaked; m->stack_trace_id = StackDepotPut(stack); m->requested_size = size; atomic_store(reinterpret_cast(m), 1, memory_order_relaxed); } static void RegisterDeallocation(void *p) { if (!p) return; ChunkMetadata *m = Metadata(p); CHECK(m); atomic_store(reinterpret_cast(m), 0, memory_order_relaxed); } void *Allocate(const StackTrace &stack, uptr size, uptr alignment, bool cleared) { if (size == 0) size = 1; if (size > kMaxAllowedMallocSize) { Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size); return 0; } void *p = allocator.Allocate(&cache, size, alignment, false); // Do not rely on the allocator to clear the memory (it's slow). if (cleared && allocator.FromPrimary(p)) memset(p, 0, size); RegisterAllocation(stack, p, size); if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(p, size); return p; } void Deallocate(void *p) { if (&__sanitizer_free_hook) __sanitizer_free_hook(p); RegisterDeallocation(p); allocator.Deallocate(&cache, p); } void *Reallocate(const StackTrace &stack, void *p, uptr new_size, uptr alignment) { RegisterDeallocation(p); if (new_size > kMaxAllowedMallocSize) { Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size); allocator.Deallocate(&cache, p); return 0; } p = allocator.Reallocate(&cache, p, new_size, alignment); RegisterAllocation(stack, p, new_size); return p; } void GetAllocatorCacheRange(uptr *begin, uptr *end) { *begin = (uptr)&cache; *end = *begin + sizeof(cache); } uptr GetMallocUsableSize(const void *p) { ChunkMetadata *m = Metadata(p); if (!m) return 0; return m->requested_size; } ///// Interface to the common LSan module. ///// void LockAllocator() { allocator.ForceLock(); } void UnlockAllocator() { allocator.ForceUnlock(); } void GetAllocatorGlobalRange(uptr *begin, uptr *end) { *begin = (uptr)&allocator; *end = *begin + sizeof(allocator); } uptr PointsIntoChunk(void* p) { uptr addr = reinterpret_cast(p); uptr chunk = reinterpret_cast(allocator.GetBlockBeginFastLocked(p)); if (!chunk) return 0; // LargeMmapAllocator considers pointers to the meta-region of a chunk to be // valid, but we don't want that. if (addr < chunk) return 0; ChunkMetadata *m = Metadata(reinterpret_cast(chunk)); CHECK(m); if (!m->allocated) return 0; if (addr < chunk + m->requested_size) return chunk; if (IsSpecialCaseOfOperatorNew0(chunk, m->requested_size, addr)) return chunk; return 0; } uptr GetUserBegin(uptr chunk) { return chunk; } LsanMetadata::LsanMetadata(uptr chunk) { metadata_ = Metadata(reinterpret_cast(chunk)); CHECK(metadata_); } bool LsanMetadata::allocated() const { return reinterpret_cast(metadata_)->allocated; } ChunkTag LsanMetadata::tag() const { return reinterpret_cast(metadata_)->tag; } void LsanMetadata::set_tag(ChunkTag value) { reinterpret_cast(metadata_)->tag = value; } uptr LsanMetadata::requested_size() const { return reinterpret_cast(metadata_)->requested_size; } u32 LsanMetadata::stack_trace_id() const { return reinterpret_cast(metadata_)->stack_trace_id; } void ForEachChunk(ForEachChunkCallback callback, void *arg) { allocator.ForEachChunk(callback, arg); } IgnoreObjectResult IgnoreObjectLocked(const void *p) { void *chunk = allocator.GetBlockBegin(p); if (!chunk || p < chunk) return kIgnoreObjectInvalid; ChunkMetadata *m = Metadata(chunk); CHECK(m); if (m->allocated && (uptr)p < (uptr)chunk + m->requested_size) { if (m->tag == kIgnored) return kIgnoreObjectAlreadyIgnored; m->tag = kIgnored; return kIgnoreObjectSuccess; } else { return kIgnoreObjectInvalid; } } } // namespace __lsan using namespace __lsan; extern "C" { SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_current_allocated_bytes() { uptr stats[AllocatorStatCount]; allocator.GetStats(stats); return stats[AllocatorStatAllocated]; } SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_heap_size() { uptr stats[AllocatorStatCount]; allocator.GetStats(stats); return stats[AllocatorStatMapped]; } SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_free_bytes() { return 0; } SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_unmapped_bytes() { return 0; } SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; } SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_get_ownership(const void *p) { return Metadata(p) != 0; } SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_allocated_size(const void *p) { return GetMallocUsableSize(p); } } // extern "C" Index: projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan_common.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan_common.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan_common.cc (revision 279194) @@ -1,711 +1,688 @@ //=-- lsan_common.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 LeakSanitizer. // Implementation of common leak checking functionality. // //===----------------------------------------------------------------------===// #include "lsan_common.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_procmaps.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_stoptheworld.h" #include "sanitizer_common/sanitizer_suppressions.h" #include "sanitizer_common/sanitizer_report_decorator.h" #if CAN_SANITIZE_LEAKS namespace __lsan { // This mutex is used to prevent races between DoLeakCheck and IgnoreObject, and // also to protect the global list of root regions. BlockingMutex global_mutex(LINKER_INITIALIZED); THREADLOCAL int disable_counter; bool DisabledInThisThread() { return disable_counter > 0; } Flags lsan_flags; void Flags::SetDefaults() { #define LSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; #include "lsan_flags.inc" #undef LSAN_FLAG } -static void RegisterLsanFlags(FlagParser *parser, Flags *f) { +void RegisterLsanFlags(FlagParser *parser, Flags *f) { #define LSAN_FLAG(Type, Name, DefaultValue, Description) \ RegisterFlag(parser, #Name, Description, &f->Name); #include "lsan_flags.inc" #undef LSAN_FLAG } -static void InitializeFlags(bool standalone) { - Flags *f = flags(); - FlagParser parser; - RegisterLsanFlags(&parser, f); - RegisterCommonFlags(&parser); - - f->SetDefaults(); - - // Set defaults for common flags (only in standalone mode) and parse - // them from LSAN_OPTIONS. - if (standalone) { - SetCommonFlagsDefaults(); - CommonFlags cf; - cf.CopyFrom(*common_flags()); - cf.external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH"); - cf.malloc_context_size = 30; - cf.detect_leaks = true; - OverrideCommonFlags(cf); - } - - bool help_before = common_flags()->help; - - const char *options = GetEnv("LSAN_OPTIONS"); - parser.ParseString(options); - - SetVerbosity(common_flags()->verbosity); - - if (Verbosity()) ReportUnrecognizedFlags(); - - if (!help_before && common_flags()->help) - parser.PrintFlagDescriptions(); -} - #define LOG_POINTERS(...) \ do { \ if (flags()->log_pointers) Report(__VA_ARGS__); \ } while (0); #define LOG_THREADS(...) \ do { \ if (flags()->log_threads) Report(__VA_ARGS__); \ } while (0); -static bool suppressions_inited = false; +ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)]; +static SuppressionContext *suppression_ctx = nullptr; +static const char kSuppressionLeak[] = "leak"; +static const char *kSuppressionTypes[] = { kSuppressionLeak }; void InitializeSuppressions() { - CHECK(!suppressions_inited); - SuppressionContext::InitIfNecessary(); + CHECK_EQ(nullptr, suppression_ctx); + suppression_ctx = new (suppression_placeholder) // NOLINT + SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); + suppression_ctx->ParseFromFile(flags()->suppressions); if (&__lsan_default_suppressions) - SuppressionContext::Get()->Parse(__lsan_default_suppressions()); - suppressions_inited = true; + suppression_ctx->Parse(__lsan_default_suppressions()); } +static SuppressionContext *GetSuppressionContext() { + CHECK(suppression_ctx); + return suppression_ctx; +} + struct RootRegion { const void *begin; uptr size; }; InternalMmapVector *root_regions; void InitializeRootRegions() { CHECK(!root_regions); ALIGNED(64) static char placeholder[sizeof(InternalMmapVector)]; root_regions = new(placeholder) InternalMmapVector(1); } -void InitCommonLsan(bool standalone) { - InitializeFlags(standalone); +void InitCommonLsan() { InitializeRootRegions(); if (common_flags()->detect_leaks) { // Initialization which can fail or print warnings should only be done if // LSan is actually enabled. InitializeSuppressions(); InitializePlatformSpecificModules(); } } class Decorator: public __sanitizer::SanitizerCommonDecorator { public: Decorator() : SanitizerCommonDecorator() { } const char *Error() { return Red(); } const char *Leak() { return Blue(); } const char *End() { return Default(); } }; static inline bool CanBeAHeapPointer(uptr p) { // Since our heap is located in mmap-ed memory, we can assume a sensible lower // bound on heap addresses. const uptr kMinAddress = 4 * 4096; if (p < kMinAddress) return false; -#ifdef __x86_64__ +#if defined(__x86_64__) // Accept only canonical form user-space addresses. return ((p >> 47) == 0); +#elif defined(__mips64) + return ((p >> 40) == 0); #else return true; #endif } // Scans the memory range, looking for byte patterns that point into allocator // chunks. Marks those chunks with |tag| and adds them to |frontier|. // There are two usage modes for this function: finding reachable or ignored // chunks (|tag| = kReachable or kIgnored) and finding indirectly leaked chunks // (|tag| = kIndirectlyLeaked). In the second case, there's no flood fill, // so |frontier| = 0. void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier, const char *region_type, ChunkTag tag) { const uptr alignment = flags()->pointer_alignment(); LOG_POINTERS("Scanning %s range %p-%p.\n", region_type, begin, end); uptr pp = begin; if (pp % alignment) pp = pp + alignment - pp % alignment; for (; pp + sizeof(void *) <= end; pp += alignment) { // NOLINT void *p = *reinterpret_cast(pp); if (!CanBeAHeapPointer(reinterpret_cast(p))) continue; uptr chunk = PointsIntoChunk(p); if (!chunk) continue; // Pointers to self don't count. This matters when tag == kIndirectlyLeaked. if (chunk == begin) continue; LsanMetadata m(chunk); // Reachable beats ignored beats leaked. if (m.tag() == kReachable) continue; if (m.tag() == kIgnored && tag != kReachable) continue; // Do this check relatively late so we can log only the interesting cases. if (!flags()->use_poisoned && WordIsPoisoned(pp)) { LOG_POINTERS( "%p is poisoned: ignoring %p pointing into chunk %p-%p of size " "%zu.\n", pp, p, chunk, chunk + m.requested_size(), m.requested_size()); continue; } m.set_tag(tag); LOG_POINTERS("%p: found %p pointing into chunk %p-%p of size %zu.\n", pp, p, chunk, chunk + m.requested_size(), m.requested_size()); if (frontier) frontier->push_back(chunk); } } void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) { Frontier *frontier = reinterpret_cast(arg); ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable); } // Scans thread data (stacks and TLS) for heap pointers. static void ProcessThreads(SuspendedThreadsList const &suspended_threads, Frontier *frontier) { InternalScopedBuffer registers(SuspendedThreadsList::RegisterCount()); uptr registers_begin = reinterpret_cast(registers.data()); uptr registers_end = registers_begin + registers.size(); for (uptr i = 0; i < suspended_threads.thread_count(); i++) { uptr os_id = static_cast(suspended_threads.GetThreadID(i)); LOG_THREADS("Processing thread %d.\n", os_id); uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end; bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end, &tls_begin, &tls_end, &cache_begin, &cache_end); if (!thread_found) { // If a thread can't be found in the thread registry, it's probably in the // process of destruction. Log this event and move on. LOG_THREADS("Thread %d not found in registry.\n", os_id); continue; } uptr sp; bool have_registers = (suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0); if (!have_registers) { Report("Unable to get registers from thread %d.\n"); // If unable to get SP, consider the entire stack to be reachable. sp = stack_begin; } if (flags()->use_registers && have_registers) ScanRangeForPointers(registers_begin, registers_end, frontier, "REGISTERS", kReachable); if (flags()->use_stacks) { LOG_THREADS("Stack at %p-%p (SP = %p).\n", stack_begin, stack_end, sp); if (sp < stack_begin || sp >= stack_end) { // SP is outside the recorded stack range (e.g. the thread is running a // signal handler on alternate stack). Again, consider the entire stack // range to be reachable. LOG_THREADS("WARNING: stack pointer not in stack range.\n"); } else { // Shrink the stack range to ignore out-of-scope values. stack_begin = sp; } ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK", kReachable); ForEachExtraStackRange(os_id, ForEachExtraStackRangeCb, frontier); } if (flags()->use_tls) { LOG_THREADS("TLS at %p-%p.\n", tls_begin, tls_end); if (cache_begin == cache_end) { ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable); } else { // Because LSan should not be loaded with dlopen(), we can assume // that allocator cache will be part of static TLS image. CHECK_LE(tls_begin, cache_begin); CHECK_GE(tls_end, cache_end); if (tls_begin < cache_begin) ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS", kReachable); if (tls_end > cache_end) ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable); } } } } static void ProcessRootRegion(Frontier *frontier, uptr root_begin, uptr root_end) { MemoryMappingLayout proc_maps(/*cache_enabled*/true); uptr begin, end, prot; while (proc_maps.Next(&begin, &end, /*offset*/ 0, /*filename*/ 0, /*filename_size*/ 0, &prot)) { uptr intersection_begin = Max(root_begin, begin); uptr intersection_end = Min(end, root_end); if (intersection_begin >= intersection_end) continue; bool is_readable = prot & MemoryMappingLayout::kProtectionRead; LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n", root_begin, root_end, begin, end, is_readable ? "readable" : "unreadable"); if (is_readable) ScanRangeForPointers(intersection_begin, intersection_end, frontier, "ROOT", kReachable); } } // Scans root regions for heap pointers. static void ProcessRootRegions(Frontier *frontier) { if (!flags()->use_root_regions) return; CHECK(root_regions); for (uptr i = 0; i < root_regions->size(); i++) { RootRegion region = (*root_regions)[i]; uptr begin_addr = reinterpret_cast(region.begin); ProcessRootRegion(frontier, begin_addr, begin_addr + region.size); } } static void FloodFillTag(Frontier *frontier, ChunkTag tag) { while (frontier->size()) { uptr next_chunk = frontier->back(); frontier->pop_back(); LsanMetadata m(next_chunk); ScanRangeForPointers(next_chunk, next_chunk + m.requested_size(), frontier, "HEAP", tag); } } // ForEachChunk callback. If the chunk is marked as leaked, marks all chunks // which are reachable from it as indirectly leaked. static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) { chunk = GetUserBegin(chunk); LsanMetadata m(chunk); if (m.allocated() && m.tag() != kReachable) { ScanRangeForPointers(chunk, chunk + m.requested_size(), /* frontier */ 0, "HEAP", kIndirectlyLeaked); } } // ForEachChunk callback. If chunk is marked as ignored, adds its address to // frontier. static void CollectIgnoredCb(uptr chunk, void *arg) { CHECK(arg); chunk = GetUserBegin(chunk); LsanMetadata m(chunk); if (m.allocated() && m.tag() == kIgnored) reinterpret_cast(arg)->push_back(chunk); } // Sets the appropriate tag on each chunk. static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) { // Holds the flood fill frontier. Frontier frontier(1); ProcessGlobalRegions(&frontier); ProcessThreads(suspended_threads, &frontier); ProcessRootRegions(&frontier); FloodFillTag(&frontier, kReachable); // The check here is relatively expensive, so we do this in a separate flood // fill. That way we can skip the check for chunks that are reachable // otherwise. LOG_POINTERS("Processing platform-specific allocations.\n"); ProcessPlatformSpecificAllocations(&frontier); FloodFillTag(&frontier, kReachable); LOG_POINTERS("Scanning ignored chunks.\n"); CHECK_EQ(0, frontier.size()); ForEachChunk(CollectIgnoredCb, &frontier); FloodFillTag(&frontier, kIgnored); // Iterate over leaked chunks and mark those that are reachable from other // leaked chunks. LOG_POINTERS("Scanning leaked chunks.\n"); ForEachChunk(MarkIndirectlyLeakedCb, 0 /* arg */); } static void PrintStackTraceById(u32 stack_trace_id) { CHECK(stack_trace_id); StackDepotGet(stack_trace_id).Print(); } // ForEachChunk callback. Aggregates information about unreachable chunks into // a LeakReport. static void CollectLeaksCb(uptr chunk, void *arg) { CHECK(arg); LeakReport *leak_report = reinterpret_cast(arg); chunk = GetUserBegin(chunk); LsanMetadata m(chunk); if (!m.allocated()) return; if (m.tag() == kDirectlyLeaked || m.tag() == kIndirectlyLeaked) { u32 resolution = flags()->resolution; u32 stack_trace_id = 0; if (resolution > 0) { StackTrace stack = StackDepotGet(m.stack_trace_id()); stack.size = Min(stack.size, resolution); stack_trace_id = StackDepotPut(stack); } else { stack_trace_id = m.stack_trace_id(); } leak_report->AddLeakedChunk(chunk, stack_trace_id, m.requested_size(), m.tag()); } } static void PrintMatchedSuppressions() { InternalMmapVector matched(1); - SuppressionContext::Get()->GetMatched(&matched); + GetSuppressionContext()->GetMatched(&matched); if (!matched.size()) return; const char *line = "-----------------------------------------------------"; Printf("%s\n", line); Printf("Suppressions used:\n"); Printf(" count bytes template\n"); for (uptr i = 0; i < matched.size(); i++) Printf("%7zu %10zu %s\n", static_cast(matched[i]->hit_count), matched[i]->weight, matched[i]->templ); Printf("%s\n\n", line); } struct DoLeakCheckParam { bool success; LeakReport leak_report; }; static void DoLeakCheckCallback(const SuspendedThreadsList &suspended_threads, void *arg) { DoLeakCheckParam *param = reinterpret_cast(arg); CHECK(param); CHECK(!param->success); ClassifyAllChunks(suspended_threads); ForEachChunk(CollectLeaksCb, ¶m->leak_report); param->success = true; } void DoLeakCheck() { EnsureMainThreadIDIsCorrect(); BlockingMutexLock l(&global_mutex); static bool already_done; if (already_done) return; already_done = true; if (&__lsan_is_turned_off && __lsan_is_turned_off()) return; DoLeakCheckParam param; param.success = false; LockThreadRegistry(); LockAllocator(); StopTheWorld(DoLeakCheckCallback, ¶m); UnlockAllocator(); UnlockThreadRegistry(); if (!param.success) { Report("LeakSanitizer has encountered a fatal error.\n"); Die(); } param.leak_report.ApplySuppressions(); uptr unsuppressed_count = param.leak_report.UnsuppressedLeakCount(); if (unsuppressed_count > 0) { Decorator d; Printf("\n" "=================================================================" "\n"); Printf("%s", d.Error()); Report("ERROR: LeakSanitizer: detected memory leaks\n"); Printf("%s", d.End()); param.leak_report.ReportTopLeaks(flags()->max_leaks); } if (common_flags()->print_suppressions) PrintMatchedSuppressions(); if (unsuppressed_count > 0) { param.leak_report.PrintSummary(); if (flags()->exitcode) { if (common_flags()->coverage) __sanitizer_cov_dump(); internal__exit(flags()->exitcode); } } } static Suppression *GetSuppressionForAddr(uptr addr) { Suppression *s = nullptr; // Suppress by module name. const char *module_name; uptr module_offset; + SuppressionContext *suppressions = GetSuppressionContext(); if (Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(addr, &module_name, &module_offset) && - SuppressionContext::Get()->Match(module_name, SuppressionLeak, &s)) + suppressions->Match(module_name, kSuppressionLeak, &s)) return s; // Suppress by file or function name. SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr); for (SymbolizedStack *cur = frames; cur; cur = cur->next) { - if (SuppressionContext::Get()->Match(cur->info.function, SuppressionLeak, - &s) || - SuppressionContext::Get()->Match(cur->info.file, SuppressionLeak, &s)) { + if (suppressions->Match(cur->info.function, kSuppressionLeak, &s) || + suppressions->Match(cur->info.file, kSuppressionLeak, &s)) { break; } } frames->ClearAll(); return s; } static Suppression *GetSuppressionForStack(u32 stack_trace_id) { StackTrace stack = StackDepotGet(stack_trace_id); for (uptr i = 0; i < stack.size; i++) { Suppression *s = GetSuppressionForAddr( StackTrace::GetPreviousInstructionPc(stack.trace[i])); if (s) return s; } return 0; } ///// LeakReport implementation. ///// // A hard limit on the number of distinct leaks, to avoid quadratic complexity // in LeakReport::AddLeakedChunk(). We don't expect to ever see this many leaks // in real-world applications. // FIXME: Get rid of this limit by changing the implementation of LeakReport to // use a hash table. const uptr kMaxLeaksConsidered = 5000; void LeakReport::AddLeakedChunk(uptr chunk, u32 stack_trace_id, uptr leaked_size, ChunkTag tag) { CHECK(tag == kDirectlyLeaked || tag == kIndirectlyLeaked); bool is_directly_leaked = (tag == kDirectlyLeaked); uptr i; for (i = 0; i < leaks_.size(); i++) { if (leaks_[i].stack_trace_id == stack_trace_id && leaks_[i].is_directly_leaked == is_directly_leaked) { leaks_[i].hit_count++; leaks_[i].total_size += leaked_size; break; } } if (i == leaks_.size()) { if (leaks_.size() == kMaxLeaksConsidered) return; Leak leak = { next_id_++, /* hit_count */ 1, leaked_size, stack_trace_id, is_directly_leaked, /* is_suppressed */ false }; leaks_.push_back(leak); } if (flags()->report_objects) { LeakedObject obj = {leaks_[i].id, chunk, leaked_size}; leaked_objects_.push_back(obj); } } static bool LeakComparator(const Leak &leak1, const Leak &leak2) { if (leak1.is_directly_leaked == leak2.is_directly_leaked) return leak1.total_size > leak2.total_size; else return leak1.is_directly_leaked; } void LeakReport::ReportTopLeaks(uptr num_leaks_to_report) { CHECK(leaks_.size() <= kMaxLeaksConsidered); Printf("\n"); if (leaks_.size() == kMaxLeaksConsidered) Printf("Too many leaks! Only the first %zu leaks encountered will be " "reported.\n", kMaxLeaksConsidered); uptr unsuppressed_count = UnsuppressedLeakCount(); if (num_leaks_to_report > 0 && num_leaks_to_report < unsuppressed_count) Printf("The %zu top leak(s):\n", num_leaks_to_report); InternalSort(&leaks_, leaks_.size(), LeakComparator); uptr leaks_reported = 0; for (uptr i = 0; i < leaks_.size(); i++) { if (leaks_[i].is_suppressed) continue; PrintReportForLeak(i); leaks_reported++; if (leaks_reported == num_leaks_to_report) break; } if (leaks_reported < unsuppressed_count) { uptr remaining = unsuppressed_count - leaks_reported; Printf("Omitting %zu more leak(s).\n", remaining); } } void LeakReport::PrintReportForLeak(uptr index) { Decorator d; Printf("%s", d.Leak()); Printf("%s leak of %zu byte(s) in %zu object(s) allocated from:\n", leaks_[index].is_directly_leaked ? "Direct" : "Indirect", leaks_[index].total_size, leaks_[index].hit_count); Printf("%s", d.End()); PrintStackTraceById(leaks_[index].stack_trace_id); if (flags()->report_objects) { Printf("Objects leaked above:\n"); PrintLeakedObjectsForLeak(index); Printf("\n"); } } void LeakReport::PrintLeakedObjectsForLeak(uptr index) { u32 leak_id = leaks_[index].id; for (uptr j = 0; j < leaked_objects_.size(); j++) { if (leaked_objects_[j].leak_id == leak_id) Printf("%p (%zu bytes)\n", leaked_objects_[j].addr, leaked_objects_[j].size); } } void LeakReport::PrintSummary() { CHECK(leaks_.size() <= kMaxLeaksConsidered); uptr bytes = 0, allocations = 0; for (uptr i = 0; i < leaks_.size(); i++) { if (leaks_[i].is_suppressed) continue; bytes += leaks_[i].total_size; allocations += leaks_[i].hit_count; } InternalScopedString summary(kMaxSummaryLength); summary.append("%zu byte(s) leaked in %zu allocation(s).", bytes, allocations); ReportErrorSummary(summary.data()); } void LeakReport::ApplySuppressions() { for (uptr i = 0; i < leaks_.size(); i++) { Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id); if (s) { s->weight += leaks_[i].total_size; s->hit_count += leaks_[i].hit_count; leaks_[i].is_suppressed = true; } } } uptr LeakReport::UnsuppressedLeakCount() { uptr result = 0; for (uptr i = 0; i < leaks_.size(); i++) if (!leaks_[i].is_suppressed) result++; return result; } } // namespace __lsan #endif // CAN_SANITIZE_LEAKS using namespace __lsan; // NOLINT extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __lsan_ignore_object(const void *p) { #if CAN_SANITIZE_LEAKS if (!common_flags()->detect_leaks) return; // Cannot use PointsIntoChunk or LsanMetadata here, since the allocator is not // locked. BlockingMutexLock l(&global_mutex); IgnoreObjectResult res = IgnoreObjectLocked(p); if (res == kIgnoreObjectInvalid) VReport(1, "__lsan_ignore_object(): no heap object found at %p", p); if (res == kIgnoreObjectAlreadyIgnored) VReport(1, "__lsan_ignore_object(): " "heap object at %p is already being ignored\n", p); if (res == kIgnoreObjectSuccess) VReport(1, "__lsan_ignore_object(): ignoring heap object at %p\n", p); #endif // CAN_SANITIZE_LEAKS } SANITIZER_INTERFACE_ATTRIBUTE void __lsan_register_root_region(const void *begin, uptr size) { #if CAN_SANITIZE_LEAKS BlockingMutexLock l(&global_mutex); CHECK(root_regions); RootRegion region = {begin, size}; root_regions->push_back(region); VReport(1, "Registered root region at %p of size %llu\n", begin, size); #endif // CAN_SANITIZE_LEAKS } SANITIZER_INTERFACE_ATTRIBUTE void __lsan_unregister_root_region(const void *begin, uptr size) { #if CAN_SANITIZE_LEAKS BlockingMutexLock l(&global_mutex); CHECK(root_regions); bool removed = false; for (uptr i = 0; i < root_regions->size(); i++) { RootRegion region = (*root_regions)[i]; if (region.begin == begin && region.size == size) { removed = true; uptr last_index = root_regions->size() - 1; (*root_regions)[i] = (*root_regions)[last_index]; root_regions->pop_back(); VReport(1, "Unregistered root region at %p of size %llu\n", begin, size); break; } } if (!removed) { Report( "__lsan_unregister_root_region(): region at %p of size %llu has not " "been registered.\n", begin, size); Die(); } #endif // CAN_SANITIZE_LEAKS } SANITIZER_INTERFACE_ATTRIBUTE void __lsan_disable() { #if CAN_SANITIZE_LEAKS __lsan::disable_counter++; #endif } SANITIZER_INTERFACE_ATTRIBUTE void __lsan_enable() { #if CAN_SANITIZE_LEAKS if (!__lsan::disable_counter && common_flags()->detect_leaks) { Report("Unmatched call to __lsan_enable().\n"); Die(); } __lsan::disable_counter--; #endif } SANITIZER_INTERFACE_ATTRIBUTE void __lsan_do_leak_check() { #if CAN_SANITIZE_LEAKS if (common_flags()->detect_leaks) __lsan::DoLeakCheck(); #endif // CAN_SANITIZE_LEAKS } #if !SANITIZER_SUPPORTS_WEAK_HOOKS SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE int __lsan_is_turned_off() { return 0; } #endif } // extern "C" Index: projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan_common.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan_common.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan_common.h (revision 279194) @@ -1,177 +1,183 @@ //=-- lsan_common.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 LeakSanitizer. // Private LSan header. // //===----------------------------------------------------------------------===// #ifndef LSAN_COMMON_H #define LSAN_COMMON_H #include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_platform.h" #include "sanitizer_common/sanitizer_symbolizer.h" -#if SANITIZER_LINUX && defined(__x86_64__) && (SANITIZER_WORDSIZE == 64) +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips64)) \ + && (SANITIZER_WORDSIZE == 64) #define CAN_SANITIZE_LEAKS 1 #else #define CAN_SANITIZE_LEAKS 0 #endif +namespace __sanitizer { +class FlagParser; +} + namespace __lsan { // Chunk tags. enum ChunkTag { kDirectlyLeaked = 0, // default kIndirectlyLeaked = 1, kReachable = 2, kIgnored = 3 }; struct Flags { #define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name; #include "lsan_flags.inc" #undef LSAN_FLAG void SetDefaults(); uptr pointer_alignment() const { return use_unaligned ? 1 : sizeof(uptr); } }; extern Flags lsan_flags; inline Flags *flags() { return &lsan_flags; } +void RegisterLsanFlags(FlagParser *parser, Flags *f); struct Leak { u32 id; uptr hit_count; uptr total_size; u32 stack_trace_id; bool is_directly_leaked; bool is_suppressed; }; struct LeakedObject { u32 leak_id; uptr addr; uptr size; }; // Aggregates leaks by stack trace prefix. class LeakReport { public: LeakReport() : next_id_(0), leaks_(1), leaked_objects_(1) {} void AddLeakedChunk(uptr chunk, u32 stack_trace_id, uptr leaked_size, ChunkTag tag); void ReportTopLeaks(uptr max_leaks); void PrintSummary(); void ApplySuppressions(); uptr UnsuppressedLeakCount(); private: void PrintReportForLeak(uptr index); void PrintLeakedObjectsForLeak(uptr index); u32 next_id_; InternalMmapVector leaks_; InternalMmapVector leaked_objects_; }; typedef InternalMmapVector Frontier; // Platform-specific functions. void InitializePlatformSpecificModules(); void ProcessGlobalRegions(Frontier *frontier); void ProcessPlatformSpecificAllocations(Frontier *frontier); void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier, const char *region_type, ChunkTag tag); enum IgnoreObjectResult { kIgnoreObjectSuccess, kIgnoreObjectAlreadyIgnored, kIgnoreObjectInvalid }; // Functions called from the parent tool. -void InitCommonLsan(bool standalone); +void InitCommonLsan(); void DoLeakCheck(); bool DisabledInThisThread(); // Special case for "new T[0]" where T is a type with DTOR. // new T[0] will allocate one word for the array size (0) and store a pointer // to the end of allocated chunk. inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size, uptr addr) { return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr && *reinterpret_cast(chunk_beg) == 0; } // The following must be implemented in the parent tool. void ForEachChunk(ForEachChunkCallback callback, void *arg); // Returns the address range occupied by the global allocator object. void GetAllocatorGlobalRange(uptr *begin, uptr *end); // Wrappers for allocator's ForceLock()/ForceUnlock(). void LockAllocator(); void UnlockAllocator(); // Returns true if [addr, addr + sizeof(void *)) is poisoned. bool WordIsPoisoned(uptr addr); // Wrappers for ThreadRegistry access. void LockThreadRegistry(); void UnlockThreadRegistry(); bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *cache_end); void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback, void *arg); // If called from the main thread, updates the main thread's TID in the thread // registry. We need this to handle processes that fork() without a subsequent // exec(), which invalidates the recorded TID. To update it, we must call // gettid() from the main thread. Our solution is to call this function before // leak checking and also before every call to pthread_create() (to handle cases // where leak checking is initiated from a non-main thread). void EnsureMainThreadIDIsCorrect(); // If p points into a chunk that has been allocated to the user, returns its // user-visible address. Otherwise, returns 0. uptr PointsIntoChunk(void *p); // Returns address of user-visible chunk contained in this allocator chunk. uptr GetUserBegin(uptr chunk); // Helper for __lsan_ignore_object(). IgnoreObjectResult IgnoreObjectLocked(const void *p); // Wrapper for chunk metadata operations. class LsanMetadata { public: // Constructor accepts address of user-visible chunk. explicit LsanMetadata(uptr chunk); bool allocated() const; ChunkTag tag() const; void set_tag(ChunkTag value); uptr requested_size() const; u32 stack_trace_id() const; private: void *metadata_; }; } // namespace __lsan extern "C" { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE int __lsan_is_turned_off(); SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char *__lsan_default_suppressions(); } // extern "C" #endif // LSAN_COMMON_H Index: projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan_flags.inc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan_flags.inc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/lsan/lsan_flags.inc (revision 279194) @@ -1,44 +1,45 @@ //===-- lsan_flags.inc ------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // LSan runtime flags. // //===----------------------------------------------------------------------===// #ifndef LSAN_FLAG # error "Define LSAN_FLAG prior to including this file!" #endif // LSAN_FLAG(Type, Name, DefaultValue, Description) // See COMMON_FLAG in sanitizer_flags.inc for more details. LSAN_FLAG(bool, report_objects, false, "Print addresses of leaked objects after main leak report.") LSAN_FLAG( int, resolution, 0, "Aggregate two objects into one leak if this many stack frames match. If " "zero, the entire stack trace must match.") LSAN_FLAG(int, max_leaks, 0, "The number of leaks reported.") LSAN_FLAG(int, exitcode, 23, "If nonzero kill the process with this exit code upon finding leaks.") // Flags controlling the root set of reachable memory. LSAN_FLAG(bool, use_globals, true, "Root set: include global variables (.data and .bss)") LSAN_FLAG(bool, use_stacks, true, "Root set: include thread stacks") LSAN_FLAG(bool, use_registers, true, "Root set: include thread registers") LSAN_FLAG(bool, use_tls, true, "Root set: include TLS and thread-specific storage") LSAN_FLAG(bool, use_root_regions, true, "Root set: include regions added via __lsan_register_root_region().") LSAN_FLAG(bool, use_unaligned, false, "Consider unaligned pointers valid.") LSAN_FLAG(bool, use_poisoned, false, "Consider pointers found in poisoned memory to be valid.") LSAN_FLAG(bool, log_pointers, false, "Debug logging") LSAN_FLAG(bool, log_threads, false, "Debug logging") +LSAN_FLAG(const char *, suppressions, "", "Suppressions file name.") Index: projects/clang360-import/contrib/compiler-rt/lib/msan/msan.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/msan/msan.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/msan/msan.cc (revision 279194) @@ -1,610 +1,610 @@ //===-- msan.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 MemorySanitizer. // // MemorySanitizer runtime. //===----------------------------------------------------------------------===// #include "msan.h" #include "msan_chained_origin_depot.h" #include "msan_origin.h" #include "msan_thread.h" #include "msan_poisoning.h" #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_procmaps.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_symbolizer.h" #include "sanitizer_common/sanitizer_stackdepot.h" // ACHTUNG! No system header includes in this file. using namespace __sanitizer; // Globals. static THREADLOCAL int msan_expect_umr = 0; static THREADLOCAL int msan_expected_umr_found = 0; // Function argument shadow. Each argument starts at the next available 8-byte // aligned address. SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64 __msan_param_tls[kMsanParamTlsSize / sizeof(u64)]; // Function argument origin. Each argument starts at the same offset as the // corresponding shadow in (__msan_param_tls). Slightly weird, but changing this // would break compatibility with older prebuilt binaries. SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSize / sizeof(u32)]; SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSize / sizeof(u64)]; SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u32 __msan_retval_origin_tls; SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)]; SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64 __msan_va_arg_overflow_size_tls; SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u32 __msan_origin_tls; static THREADLOCAL int is_in_symbolizer; extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_track_origins; int __msan_get_track_origins() { return &__msan_track_origins ? __msan_track_origins : 0; } extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_keep_going; namespace __msan { void EnterSymbolizer() { ++is_in_symbolizer; } void ExitSymbolizer() { --is_in_symbolizer; } bool IsInSymbolizer() { return is_in_symbolizer; } static Flags msan_flags; Flags *flags() { return &msan_flags; } int msan_inited = 0; bool msan_init_is_running; int msan_report_count = 0; void (*death_callback)(void); // Array of stack origins. // FIXME: make it resizable. static const uptr kNumStackOriginDescrs = 1024 * 1024; static const char *StackOriginDescr[kNumStackOriginDescrs]; static uptr StackOriginPC[kNumStackOriginDescrs]; static atomic_uint32_t NumStackOriginDescrs; void Flags::SetDefaults() { #define MSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; #include "msan_flags.inc" #undef MSAN_FLAG } // keep_going is an old name for halt_on_error, // and it has inverse meaning. class FlagHandlerKeepGoing : public FlagHandlerBase { bool *halt_on_error_; public: explicit FlagHandlerKeepGoing(bool *halt_on_error) : halt_on_error_(halt_on_error) {} - bool Parse(const char *value) { + bool Parse(const char *value) final { bool tmp; FlagHandler h(&tmp); if (!h.Parse(value)) return false; *halt_on_error_ = !tmp; return true; } }; -void RegisterMsanFlags(FlagParser *parser, Flags *f) { +static void RegisterMsanFlags(FlagParser *parser, Flags *f) { #define MSAN_FLAG(Type, Name, DefaultValue, Description) \ RegisterFlag(parser, #Name, Description, &f->Name); #include "msan_flags.inc" #undef MSAN_FLAG FlagHandlerKeepGoing *fh_keep_going = new (FlagParser::Alloc) // NOLINT FlagHandlerKeepGoing(&f->halt_on_error); parser->RegisterHandler("keep_going", fh_keep_going, "deprecated, use halt_on_error"); } -static void InitializeFlags(Flags *f, const char *options) { +static void InitializeFlags() { + Flags *f = flags(); FlagParser parser; RegisterMsanFlags(&parser, f); RegisterCommonFlags(&parser); SetCommonFlagsDefaults(); { CommonFlags cf; cf.CopyFrom(*common_flags()); cf.external_symbolizer_path = GetEnv("MSAN_SYMBOLIZER_PATH"); cf.malloc_context_size = 20; cf.handle_ioctl = true; // FIXME: test and enable. cf.check_printf = false; cf.intercept_tls_get_addr = true; OverrideCommonFlags(cf); } f->SetDefaults(); // Override from user-specified string. if (__msan_default_options) parser.ParseString(__msan_default_options()); - parser.ParseString(options); + const char *msan_options = GetEnv("MSAN_OPTIONS"); + parser.ParseString(msan_options); + VPrintf(1, "MSAN_OPTIONS: %s\n", msan_options ? msan_options : ""); SetVerbosity(common_flags()->verbosity); if (Verbosity()) ReportUnrecognizedFlags(); if (common_flags()->help) parser.PrintFlagDescriptions(); // Check flag values: if (f->exit_code < 0 || f->exit_code > 127) { Printf("Exit code not in [0, 128) range: %d\n", f->exit_code); Die(); } if (f->origin_history_size < 0 || f->origin_history_size > Origin::kMaxDepth) { Printf( "Origin history size invalid: %d. Must be 0 (unlimited) or in [1, %d] " "range.\n", f->origin_history_size, Origin::kMaxDepth); Die(); } // Limiting to kStackDepotMaxUseCount / 2 to avoid overflow in // StackDepotHandle::inc_use_count_unsafe. if (f->origin_history_per_stack_limit < 0 || f->origin_history_per_stack_limit > kStackDepotMaxUseCount / 2) { Printf( "Origin per-stack limit invalid: %d. Must be 0 (unlimited) or in [1, " "%d] range.\n", f->origin_history_per_stack_limit, kStackDepotMaxUseCount / 2); Die(); } if (f->store_context_size < 1) f->store_context_size = 1; } void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp, bool request_fast_unwind) { MsanThread *t = GetCurrentThread(); if (!t || !StackTrace::WillUseFastUnwind(request_fast_unwind)) { // Block reports from our interceptors during _Unwind_Backtrace. SymbolizerScope sym_scope; return stack->Unwind(max_s, pc, bp, 0, 0, 0, request_fast_unwind); } stack->Unwind(max_s, pc, bp, 0, t->stack_top(), t->stack_bottom(), request_fast_unwind); } void PrintWarning(uptr pc, uptr bp) { PrintWarningWithOrigin(pc, bp, __msan_origin_tls); } void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin) { if (msan_expect_umr) { // Printf("Expected UMR\n"); __msan_origin_tls = origin; msan_expected_umr_found = 1; return; } ++msan_report_count; GET_FATAL_STACK_TRACE_PC_BP(pc, bp); u32 report_origin = (__msan_get_track_origins() && Origin::isValidId(origin)) ? origin : 0; ReportUMR(&stack, report_origin); if (__msan_get_track_origins() && !Origin::isValidId(origin)) { Printf( " ORIGIN: invalid (%x). Might be a bug in MemorySanitizer origin " "tracking.\n This could still be a bug in your code, too!\n", origin); } } void UnpoisonParam(uptr n) { internal_memset(__msan_param_tls, 0, n * sizeof(*__msan_param_tls)); } // Backup MSan runtime TLS state. // Implementation must be async-signal-safe. // Instances of this class may live on the signal handler stack, and data size // may be an issue. void ScopedThreadLocalStateBackup::Backup() { va_arg_overflow_size_tls = __msan_va_arg_overflow_size_tls; } void ScopedThreadLocalStateBackup::Restore() { // A lame implementation that only keeps essential state and resets the rest. __msan_va_arg_overflow_size_tls = va_arg_overflow_size_tls; internal_memset(__msan_param_tls, 0, sizeof(__msan_param_tls)); internal_memset(__msan_retval_tls, 0, sizeof(__msan_retval_tls)); internal_memset(__msan_va_arg_tls, 0, sizeof(__msan_va_arg_tls)); if (__msan_get_track_origins()) { internal_memset(&__msan_retval_origin_tls, 0, sizeof(__msan_retval_origin_tls)); internal_memset(__msan_param_origin_tls, 0, sizeof(__msan_param_origin_tls)); } } void UnpoisonThreadLocalState() { } const char *GetStackOriginDescr(u32 id, uptr *pc) { CHECK_LT(id, kNumStackOriginDescrs); if (pc) *pc = StackOriginPC[id]; return StackOriginDescr[id]; } u32 ChainOrigin(u32 id, StackTrace *stack) { MsanThread *t = GetCurrentThread(); if (t && t->InSignalHandler()) return id; Origin o = Origin::FromRawId(id); stack->tag = StackTrace::TAG_UNKNOWN; Origin chained = Origin::CreateChainedOrigin(o, stack); return chained.raw_id(); } } // namespace __msan // Interface. using namespace __msan; #define MSAN_MAYBE_WARNING(type, size) \ void __msan_maybe_warning_##size(type s, u32 o) { \ GET_CALLER_PC_BP_SP; \ (void) sp; \ if (UNLIKELY(s)) { \ PrintWarningWithOrigin(pc, bp, o); \ if (__msan::flags()->halt_on_error) { \ Printf("Exiting\n"); \ Die(); \ } \ } \ } MSAN_MAYBE_WARNING(u8, 1) MSAN_MAYBE_WARNING(u16, 2) MSAN_MAYBE_WARNING(u32, 4) MSAN_MAYBE_WARNING(u64, 8) #define MSAN_MAYBE_STORE_ORIGIN(type, size) \ void __msan_maybe_store_origin_##size(type s, void *p, u32 o) { \ if (UNLIKELY(s)) { \ if (__msan_get_track_origins() > 1) { \ GET_CALLER_PC_BP_SP; \ (void) sp; \ GET_STORE_STACK_TRACE_PC_BP(pc, bp); \ o = ChainOrigin(o, &stack); \ } \ *(u32 *)MEM_TO_ORIGIN((uptr)p & ~3UL) = o; \ } \ } MSAN_MAYBE_STORE_ORIGIN(u8, 1) MSAN_MAYBE_STORE_ORIGIN(u16, 2) MSAN_MAYBE_STORE_ORIGIN(u32, 4) MSAN_MAYBE_STORE_ORIGIN(u64, 8) void __msan_warning() { GET_CALLER_PC_BP_SP; (void)sp; PrintWarning(pc, bp); if (__msan::flags()->halt_on_error) { if (__msan::flags()->print_stats) ReportStats(); Printf("Exiting\n"); Die(); } } void __msan_warning_noreturn() { GET_CALLER_PC_BP_SP; (void)sp; PrintWarning(pc, bp); if (__msan::flags()->print_stats) ReportStats(); Printf("Exiting\n"); Die(); } void __msan_init() { CHECK(!msan_init_is_running); if (msan_inited) return; msan_init_is_running = 1; SanitizerToolName = "MemorySanitizer"; SetDieCallback(MsanDie); InitTlsSize(); - const char *msan_options = GetEnv("MSAN_OPTIONS"); - InitializeFlags(&msan_flags, msan_options); + InitializeFlags(); __sanitizer_set_report_path(common_flags()->log_path); InitializeInterceptors(); InstallAtExitHandler(); // Needs __cxa_atexit interceptor. if (MSAN_REPLACE_OPERATORS_NEW_AND_DELETE) ReplaceOperatorsNewAndDelete(); DisableCoreDumperIfNecessary(); if (StackSizeIsUnlimited()) { VPrintf(1, "Unlimited stack, doing reexec\n"); // A reasonably large stack size. It is bigger than the usual 8Mb, because, // well, the program could have been run with unlimited stack for a reason. SetStackSizeLimitInBytes(32 * 1024 * 1024); ReExec(); } - - VPrintf(1, "MSAN_OPTIONS: %s\n", msan_options ? msan_options : ""); __msan_clear_on_return(); if (__msan_get_track_origins()) VPrintf(1, "msan_track_origins\n"); if (!InitShadow(/* map_shadow */ true, __msan_get_track_origins())) { Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n"); Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n"); Printf("FATAL: Disabling ASLR is known to cause this error.\n"); Printf("FATAL: If running under GDB, try " "'set disable-randomization off'.\n"); DumpProcessMap(); Die(); } Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer); InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); MsanTSDInit(MsanTSDDtor); MsanThread *main_thread = MsanThread::Create(0, 0); SetCurrentThread(main_thread); main_thread->ThreadStart(); VPrintf(1, "MemorySanitizer init done\n"); msan_init_is_running = 0; msan_inited = 1; } void __msan_set_exit_code(int exit_code) { flags()->exit_code = exit_code; } void __msan_set_keep_going(int keep_going) { flags()->halt_on_error = !keep_going; } void __msan_set_expect_umr(int expect_umr) { if (expect_umr) { msan_expected_umr_found = 0; } else if (!msan_expected_umr_found) { GET_CALLER_PC_BP_SP; (void)sp; GET_FATAL_STACK_TRACE_PC_BP(pc, bp); ReportExpectedUMRNotFound(&stack); Die(); } msan_expect_umr = expect_umr; } void __msan_print_shadow(const void *x, uptr size) { if (!MEM_IS_APP(x)) { Printf("Not a valid application address: %p\n", x); return; } DescribeMemoryRange(x, size); } void __msan_dump_shadow(const void *x, uptr size) { if (!MEM_IS_APP(x)) { Printf("Not a valid application address: %p\n", x); return; } unsigned char *s = (unsigned char*)MEM_TO_SHADOW(x); for (uptr i = 0; i < size; i++) { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ Printf("%x%x ", s[i] & 0xf, s[i] >> 4); #else Printf("%x%x ", s[i] >> 4, s[i] & 0xf); #endif } Printf("\n"); } sptr __msan_test_shadow(const void *x, uptr size) { if (!MEM_IS_APP(x)) return -1; unsigned char *s = (unsigned char *)MEM_TO_SHADOW((uptr)x); for (uptr i = 0; i < size; ++i) if (s[i]) return i; return -1; } void __msan_check_mem_is_initialized(const void *x, uptr size) { if (!__msan::flags()->report_umrs) return; sptr offset = __msan_test_shadow(x, size); if (offset < 0) return; GET_CALLER_PC_BP_SP; (void)sp; ReportUMRInsideAddressRange(__func__, x, size, offset); __msan::PrintWarningWithOrigin(pc, bp, __msan_get_origin(((const char *)x) + offset)); if (__msan::flags()->halt_on_error) { Printf("Exiting\n"); Die(); } } int __msan_set_poison_in_malloc(int do_poison) { int old = flags()->poison_in_malloc; flags()->poison_in_malloc = do_poison; return old; } int __msan_has_dynamic_component() { return false; } NOINLINE void __msan_clear_on_return() { __msan_param_tls[0] = 0; } void __msan_partial_poison(const void* data, void* shadow, uptr size) { internal_memcpy((void*)MEM_TO_SHADOW((uptr)data), shadow, size); } void __msan_load_unpoisoned(void *src, uptr size, void *dst) { internal_memcpy(dst, src, size); __msan_unpoison(dst, size); } void __msan_set_origin(const void *a, uptr size, u32 origin) { if (__msan_get_track_origins()) SetOrigin(a, size, origin); } // 'descr' is created at compile time and contains '----' in the beginning. // When we see descr for the first time we replace '----' with a uniq id // and set the origin to (id | (31-th bit)). void __msan_set_alloca_origin(void *a, uptr size, char *descr) { __msan_set_alloca_origin4(a, size, descr, 0); } void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc) { static const u32 dash = '-'; static const u32 first_timer = dash + (dash << 8) + (dash << 16) + (dash << 24); u32 *id_ptr = (u32*)descr; bool print = false; // internal_strstr(descr + 4, "AllocaTOTest") != 0; u32 id = *id_ptr; if (id == first_timer) { u32 idx = atomic_fetch_add(&NumStackOriginDescrs, 1, memory_order_relaxed); CHECK_LT(idx, kNumStackOriginDescrs); StackOriginDescr[idx] = descr + 4; StackOriginPC[idx] = pc; id = Origin::CreateStackOrigin(idx).raw_id(); *id_ptr = id; if (print) Printf("First time: idx=%d id=%d %s %p \n", idx, id, descr + 4, pc); } if (print) Printf("__msan_set_alloca_origin: descr=%s id=%x\n", descr + 4, id); __msan_set_origin(a, size, id); } u32 __msan_chain_origin(u32 id) { GET_CALLER_PC_BP_SP; (void)sp; GET_STORE_STACK_TRACE_PC_BP(pc, bp); return ChainOrigin(id, &stack); } u32 __msan_get_origin(const void *a) { if (!__msan_get_track_origins()) return 0; uptr x = (uptr)a; uptr aligned = x & ~3ULL; uptr origin_ptr = MEM_TO_ORIGIN(aligned); return *(u32*)origin_ptr; } u32 __msan_get_umr_origin() { return __msan_origin_tls; } u16 __sanitizer_unaligned_load16(const uu16 *p) { __msan_retval_tls[0] = *(uu16 *)MEM_TO_SHADOW((uptr)p); if (__msan_get_track_origins()) __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p)); return *p; } u32 __sanitizer_unaligned_load32(const uu32 *p) { __msan_retval_tls[0] = *(uu32 *)MEM_TO_SHADOW((uptr)p); if (__msan_get_track_origins()) __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p)); return *p; } u64 __sanitizer_unaligned_load64(const uu64 *p) { __msan_retval_tls[0] = *(uu64 *)MEM_TO_SHADOW((uptr)p); if (__msan_get_track_origins()) __msan_retval_origin_tls = GetOriginIfPoisoned((uptr)p, sizeof(*p)); return *p; } void __sanitizer_unaligned_store16(uu16 *p, u16 x) { u16 s = __msan_param_tls[1]; *(uu16 *)MEM_TO_SHADOW((uptr)p) = s; if (s && __msan_get_track_origins()) if (uu32 o = __msan_param_origin_tls[2]) SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o); *p = x; } void __sanitizer_unaligned_store32(uu32 *p, u32 x) { u32 s = __msan_param_tls[1]; *(uu32 *)MEM_TO_SHADOW((uptr)p) = s; if (s && __msan_get_track_origins()) if (uu32 o = __msan_param_origin_tls[2]) SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o); *p = x; } void __sanitizer_unaligned_store64(uu64 *p, u64 x) { u64 s = __msan_param_tls[1]; *(uu64 *)MEM_TO_SHADOW((uptr)p) = s; if (s && __msan_get_track_origins()) if (uu32 o = __msan_param_origin_tls[2]) SetOriginIfPoisoned((uptr)p, (uptr)&s, sizeof(s), o); *p = x; } void __msan_set_death_callback(void (*callback)(void)) { death_callback = callback; } #if !SANITIZER_SUPPORTS_WEAK_HOOKS extern "C" { SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char* __msan_default_options() { return ""; } } // extern "C" #endif extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_print_stack_trace() { GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME()); stack.Print(); } } // extern "C" Index: projects/clang360-import/contrib/compiler-rt/lib/msan/tests/msan_test.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/msan/tests/msan_test.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/msan/tests/msan_test.cc (revision 279194) @@ -1,4247 +1,4285 @@ //===-- msan_test.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 MemorySanitizer. // // MemorySanitizer unit tests. //===----------------------------------------------------------------------===// #ifndef MSAN_EXTERNAL_TEST_CONFIG #include "msan_test_config.h" #endif // MSAN_EXTERNAL_TEST_CONFIG #include "sanitizer_common/tests/sanitizer_test_utils.h" #include "sanitizer/allocator_interface.h" #include "sanitizer/msan_interface.h" #if defined(__FreeBSD__) # define _KERNEL // To declare 'shminfo' structure. # include # undef _KERNEL extern "C" { // doesn't declare these functions in _KERNEL mode. void *shmat(int, const void *, int); int shmget(key_t, size_t, int); int shmctl(int, int, struct shmid_ds *); int shmdt(const void *); } #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(__FreeBSD__) # include # include # include # include # include #else +# include # include # include # include # include +# include +# include # define f_namelen f_namemax // FreeBSD names this statfs field so. # define cpu_set_t cpuset_t +extern "C" { +// FreeBSD's defines mempcpy() to be a macro expanding into +// a __builtin___mempcpy_chk() call, but since Msan RTL defines it as an +// ordinary function, we can declare it here to complete the tests. +void *mempcpy(void *dest, const void *src, size_t n); +} #endif #if defined(__i386__) || defined(__x86_64__) # include # define MSAN_HAS_M128 1 #else # define MSAN_HAS_M128 0 #endif #ifdef __AVX2__ # include #endif // On FreeBSD procfs is not enabled by default. #if defined(__FreeBSD__) # define FILE_TO_READ "/bin/cat" # define DIR_TO_READ "/bin" # define SUBFILE_TO_READ "cat" # define SYMLINK_TO_READ "/usr/bin/tar" +# define SUPERUSER_GROUP "wheel" #else # define FILE_TO_READ "/proc/self/stat" # define DIR_TO_READ "/proc/self" # define SUBFILE_TO_READ "stat" # define SYMLINK_TO_READ "/proc/self/exe" +# define SUPERUSER_GROUP "root" #endif -static const size_t kPageSize = 4096; +const size_t kPageSize = 4096; +const size_t kMaxPathLength = 4096; typedef unsigned char U1; typedef unsigned short U2; // NOLINT typedef unsigned int U4; typedef unsigned long long U8; // NOLINT typedef signed char S1; typedef signed short S2; // NOLINT typedef signed int S4; typedef signed long long S8; // NOLINT #define NOINLINE __attribute__((noinline)) #define INLINE __attribute__((always_inline)) static bool TrackingOrigins() { S8 x; __msan_set_origin(&x, sizeof(x), 0x1234); U4 origin = __msan_get_origin(&x); __msan_set_origin(&x, sizeof(x), 0); return origin == 0x1234; } #define EXPECT_UMR(action) \ do { \ __msan_set_expect_umr(1); \ action; \ __msan_set_expect_umr(0); \ } while (0) #define EXPECT_UMR_O(action, origin) \ do { \ __msan_set_expect_umr(1); \ action; \ __msan_set_expect_umr(0); \ if (TrackingOrigins()) \ EXPECT_EQ(origin, __msan_get_umr_origin()); \ } while (0) #define EXPECT_POISONED(x) ExpectPoisoned(x) template void ExpectPoisoned(const T& t) { EXPECT_NE(-1, __msan_test_shadow((void*)&t, sizeof(t))); } #define EXPECT_POISONED_O(x, origin) \ ExpectPoisonedWithOrigin(x, origin) template void ExpectPoisonedWithOrigin(const T& t, unsigned origin) { EXPECT_NE(-1, __msan_test_shadow((void*)&t, sizeof(t))); if (TrackingOrigins()) EXPECT_EQ(origin, __msan_get_origin((void*)&t)); } -#define EXPECT_NOT_POISONED(x) ExpectNotPoisoned(x) +#define EXPECT_NOT_POISONED(x) EXPECT_EQ(true, TestForNotPoisoned((x))) template -void ExpectNotPoisoned(const T& t) { - EXPECT_EQ(-1, __msan_test_shadow((void*)&t, sizeof(t))); +bool TestForNotPoisoned(const T& t) { + return __msan_test_shadow((void*)&t, sizeof(t)) == -1; } static U8 poisoned_array[100]; template T *GetPoisoned(int i = 0, T val = 0) { T *res = (T*)&poisoned_array[i]; *res = val; __msan_poison(&poisoned_array[i], sizeof(T)); return res; } template T *GetPoisonedO(int i, U4 origin, T val = 0) { T *res = (T*)&poisoned_array[i]; *res = val; __msan_poison(&poisoned_array[i], sizeof(T)); __msan_set_origin(&poisoned_array[i], sizeof(T), origin); return res; } template T Poisoned(T v = 0, T s = (T)(-1)) { __msan_partial_poison(&v, &s, sizeof(T)); return v; } template NOINLINE T ReturnPoisoned() { return *GetPoisoned(); } static volatile int g_one = 1; static volatile int g_zero = 0; static volatile int g_0 = 0; static volatile int g_1 = 1; S4 a_s4[100]; S8 a_s8[100]; // Check that malloc poisons memory. // A lot of tests below depend on this. TEST(MemorySanitizerSanity, PoisonInMalloc) { int *x = (int*)malloc(sizeof(int)); EXPECT_POISONED(*x); free(x); } TEST(MemorySanitizer, NegativeTest1) { S4 *x = GetPoisoned(); if (g_one) *x = 0; EXPECT_NOT_POISONED(*x); } TEST(MemorySanitizer, PositiveTest1) { // Load to store. EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); // S->S conversions. EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); // ZExt EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(*GetPoisoned()); // Unary ops. EXPECT_POISONED(- *GetPoisoned()); EXPECT_UMR(a_s4[g_zero] = 100 / *GetPoisoned(0, 1)); a_s4[g_zero] = 1 - *GetPoisoned(); a_s4[g_zero] = 1 + *GetPoisoned(); } TEST(MemorySanitizer, Phi1) { S4 c; if (g_one) { c = *GetPoisoned(); } else { break_optimization(0); c = 0; } EXPECT_POISONED(c); } TEST(MemorySanitizer, Phi2) { S4 i = *GetPoisoned(); S4 n = g_one; EXPECT_UMR(for (; i < g_one; i++);); EXPECT_POISONED(i); } NOINLINE void Arg1ExpectUMR(S4 a1) { EXPECT_POISONED(a1); } NOINLINE void Arg2ExpectUMR(S4 a1, S4 a2) { EXPECT_POISONED(a2); } NOINLINE void Arg3ExpectUMR(S1 a1, S4 a2, S8 a3) { EXPECT_POISONED(a3); } TEST(MemorySanitizer, ArgTest) { Arg1ExpectUMR(*GetPoisoned()); Arg2ExpectUMR(0, *GetPoisoned()); Arg3ExpectUMR(0, 1, *GetPoisoned()); } TEST(MemorySanitizer, CallAndRet) { ReturnPoisoned(); ReturnPoisoned(); ReturnPoisoned(); ReturnPoisoned(); EXPECT_POISONED(ReturnPoisoned()); EXPECT_POISONED(ReturnPoisoned()); EXPECT_POISONED(ReturnPoisoned()); EXPECT_POISONED(ReturnPoisoned()); } // malloc() in the following test may be optimized to produce a compile-time // undef value. Check that we trap on the volatile assignment anyway. TEST(MemorySanitizer, DISABLED_MallocNoIdent) { S4 *x = (int*)malloc(sizeof(S4)); EXPECT_POISONED(*x); free(x); } TEST(MemorySanitizer, Malloc) { S4 *x = (int*)Ident(malloc(sizeof(S4))); EXPECT_POISONED(*x); free(x); } TEST(MemorySanitizer, Realloc) { S4 *x = (int*)Ident(realloc(0, sizeof(S4))); EXPECT_POISONED(x[0]); x[0] = 1; x = (int*)Ident(realloc(x, 2 * sizeof(S4))); EXPECT_NOT_POISONED(x[0]); // Ok, was inited before. EXPECT_POISONED(x[1]); x = (int*)Ident(realloc(x, 3 * sizeof(S4))); EXPECT_NOT_POISONED(x[0]); // Ok, was inited before. EXPECT_POISONED(x[2]); EXPECT_POISONED(x[1]); x[2] = 1; // Init this here. Check that after realloc it is poisoned again. x = (int*)Ident(realloc(x, 2 * sizeof(S4))); EXPECT_NOT_POISONED(x[0]); // Ok, was inited before. EXPECT_POISONED(x[1]); x = (int*)Ident(realloc(x, 3 * sizeof(S4))); EXPECT_POISONED(x[1]); EXPECT_POISONED(x[2]); free(x); } TEST(MemorySanitizer, Calloc) { S4 *x = (int*)Ident(calloc(1, sizeof(S4))); EXPECT_NOT_POISONED(*x); // Should not be poisoned. EXPECT_EQ(0, *x); free(x); } TEST(MemorySanitizer, CallocReturnsZeroMem) { size_t sizes[] = {16, 1000, 10000, 100000, 2100000}; for (size_t s = 0; s < sizeof(sizes)/sizeof(sizes[0]); s++) { size_t size = sizes[s]; for (size_t iter = 0; iter < 5; iter++) { char *x = Ident((char*)calloc(1, size)); EXPECT_EQ(x[0], 0); EXPECT_EQ(x[size - 1], 0); EXPECT_EQ(x[size / 2], 0); EXPECT_EQ(x[size / 3], 0); EXPECT_EQ(x[size / 4], 0); memset(x, 0x42, size); free(Ident(x)); } } } TEST(MemorySanitizer, AndOr) { U4 *p = GetPoisoned(); // We poison two bytes in the midle of a 4-byte word to make the test // correct regardless of endianness. ((U1*)p)[1] = 0; ((U1*)p)[2] = 0xff; EXPECT_NOT_POISONED(*p & 0x00ffff00); EXPECT_NOT_POISONED(*p & 0x00ff0000); EXPECT_NOT_POISONED(*p & 0x0000ff00); EXPECT_POISONED(*p & 0xff000000); EXPECT_POISONED(*p & 0x000000ff); EXPECT_POISONED(*p & 0x0000ffff); EXPECT_POISONED(*p & 0xffff0000); EXPECT_NOT_POISONED(*p | 0xff0000ff); EXPECT_NOT_POISONED(*p | 0xff00ffff); EXPECT_NOT_POISONED(*p | 0xffff00ff); EXPECT_POISONED(*p | 0xff000000); EXPECT_POISONED(*p | 0x000000ff); EXPECT_POISONED(*p | 0x0000ffff); EXPECT_POISONED(*p | 0xffff0000); EXPECT_POISONED(*GetPoisoned() & *GetPoisoned()); } template static bool applyNot(T value, T shadow) { __msan_partial_poison(&value, &shadow, sizeof(T)); return !value; } TEST(MemorySanitizer, Not) { EXPECT_NOT_POISONED(applyNot(0x0, 0x0)); EXPECT_NOT_POISONED(applyNot(0xFFFFFFFF, 0x0)); EXPECT_POISONED(applyNot(0xFFFFFFFF, 0xFFFFFFFF)); EXPECT_NOT_POISONED(applyNot(0xFF000000, 0x0FFFFFFF)); EXPECT_NOT_POISONED(applyNot(0xFF000000, 0x00FFFFFF)); EXPECT_NOT_POISONED(applyNot(0xFF000000, 0x0000FFFF)); EXPECT_NOT_POISONED(applyNot(0xFF000000, 0x00000000)); EXPECT_POISONED(applyNot(0xFF000000, 0xFF000000)); EXPECT_NOT_POISONED(applyNot(0xFF800000, 0xFF000000)); EXPECT_POISONED(applyNot(0x00008000, 0x00008000)); EXPECT_NOT_POISONED(applyNot(0x0, 0x0)); EXPECT_NOT_POISONED(applyNot(0xFF, 0xFE)); EXPECT_NOT_POISONED(applyNot(0xFF, 0x0)); EXPECT_POISONED(applyNot(0xFF, 0xFF)); EXPECT_POISONED(applyNot((void*)0xFFFFFF, (void*)(-1))); EXPECT_NOT_POISONED(applyNot((void*)0xFFFFFF, (void*)(-2))); } TEST(MemorySanitizer, Shift) { U4 *up = GetPoisoned(); ((U1*)up)[0] = 0; ((U1*)up)[3] = 0xff; EXPECT_NOT_POISONED(*up >> 30); EXPECT_NOT_POISONED(*up >> 24); EXPECT_POISONED(*up >> 23); EXPECT_POISONED(*up >> 10); EXPECT_NOT_POISONED(*up << 30); EXPECT_NOT_POISONED(*up << 24); EXPECT_POISONED(*up << 23); EXPECT_POISONED(*up << 10); S4 *sp = (S4*)up; EXPECT_NOT_POISONED(*sp >> 30); EXPECT_NOT_POISONED(*sp >> 24); EXPECT_POISONED(*sp >> 23); EXPECT_POISONED(*sp >> 10); sp = GetPoisoned(); ((S1*)sp)[1] = 0; ((S1*)sp)[2] = 0; EXPECT_POISONED(*sp >> 31); EXPECT_POISONED(100 >> *GetPoisoned()); EXPECT_POISONED(100U >> *GetPoisoned()); } NOINLINE static int GetPoisonedZero() { int *zero = new int; *zero = 0; __msan_poison(zero, sizeof(*zero)); int res = *zero; delete zero; return res; } TEST(MemorySanitizer, LoadFromDirtyAddress) { int *a = new int; *a = 0; EXPECT_UMR(break_optimization((void*)(U8)a[GetPoisonedZero()])); delete a; } TEST(MemorySanitizer, StoreToDirtyAddress) { int *a = new int; EXPECT_UMR(a[GetPoisonedZero()] = 0); break_optimization(a); delete a; } NOINLINE void StackTestFunc() { S4 p4; S4 ok4 = 1; S2 p2; S2 ok2 = 1; S1 p1; S1 ok1 = 1; break_optimization(&p4); break_optimization(&ok4); break_optimization(&p2); break_optimization(&ok2); break_optimization(&p1); break_optimization(&ok1); EXPECT_POISONED(p4); EXPECT_POISONED(p2); EXPECT_POISONED(p1); EXPECT_NOT_POISONED(ok1); EXPECT_NOT_POISONED(ok2); EXPECT_NOT_POISONED(ok4); } TEST(MemorySanitizer, StackTest) { StackTestFunc(); } NOINLINE void StackStressFunc() { int foo[10000]; break_optimization(foo); } TEST(MemorySanitizer, DISABLED_StackStressTest) { for (int i = 0; i < 1000000; i++) StackStressFunc(); } template void TestFloatingPoint() { static volatile T v; static T g[100]; break_optimization(&g); T *x = GetPoisoned(); T *y = GetPoisoned(1); EXPECT_POISONED(*x); EXPECT_POISONED((long long)*x); EXPECT_POISONED((int)*x); g[0] = *x; g[1] = *x + *y; g[2] = *x - *y; g[3] = *x * *y; } TEST(MemorySanitizer, FloatingPointTest) { TestFloatingPoint(); TestFloatingPoint(); } TEST(MemorySanitizer, DynMem) { S4 x = 0; S4 *y = GetPoisoned(); memcpy(y, &x, g_one * sizeof(S4)); EXPECT_NOT_POISONED(*y); } static char *DynRetTestStr; TEST(MemorySanitizer, DynRet) { ReturnPoisoned(); EXPECT_NOT_POISONED(atoi("0")); } TEST(MemorySanitizer, DynRet1) { ReturnPoisoned(); } struct LargeStruct { S4 x[10]; }; NOINLINE LargeStruct LargeRetTest() { LargeStruct res; res.x[0] = *GetPoisoned(); res.x[1] = *GetPoisoned(); res.x[2] = *GetPoisoned(); res.x[3] = *GetPoisoned(); res.x[4] = *GetPoisoned(); res.x[5] = *GetPoisoned(); res.x[6] = *GetPoisoned(); res.x[7] = *GetPoisoned(); res.x[8] = *GetPoisoned(); res.x[9] = *GetPoisoned(); return res; } TEST(MemorySanitizer, strcmp) { char s1[10]; char s2[10]; strncpy(s1, "foo", 10); s2[0] = 'f'; s2[1] = 'n'; EXPECT_GT(strcmp(s1, s2), 0); s2[1] = 'o'; int res; EXPECT_UMR(res = strcmp(s1, s2)); EXPECT_NOT_POISONED(res); EXPECT_EQ(strncmp(s1, s2, 1), 0); } TEST(MemorySanitizer, LargeRet) { LargeStruct a = LargeRetTest(); EXPECT_POISONED(a.x[0]); EXPECT_POISONED(a.x[9]); } TEST(MemorySanitizer, strerror) { char *buf = strerror(EINVAL); EXPECT_NOT_POISONED(strlen(buf)); buf = strerror(123456); EXPECT_NOT_POISONED(strlen(buf)); } TEST(MemorySanitizer, strerror_r) { errno = 0; char buf[1000]; char *res = (char*) (size_t) strerror_r(EINVAL, buf, sizeof(buf)); ASSERT_EQ(0, errno); if (!res) res = buf; // POSIX version success. EXPECT_NOT_POISONED(strlen(res)); } TEST(MemorySanitizer, fread) { char *x = new char[32]; FILE *f = fopen(FILE_TO_READ, "r"); ASSERT_TRUE(f != NULL); fread(x, 1, 32, f); EXPECT_NOT_POISONED(x[0]); EXPECT_NOT_POISONED(x[16]); EXPECT_NOT_POISONED(x[31]); fclose(f); delete[] x; } TEST(MemorySanitizer, read) { char *x = new char[32]; int fd = open(FILE_TO_READ, O_RDONLY); ASSERT_GT(fd, 0); int sz = read(fd, x, 32); ASSERT_EQ(sz, 32); EXPECT_NOT_POISONED(x[0]); EXPECT_NOT_POISONED(x[16]); EXPECT_NOT_POISONED(x[31]); close(fd); delete[] x; } TEST(MemorySanitizer, pread) { char *x = new char[32]; int fd = open(FILE_TO_READ, O_RDONLY); ASSERT_GT(fd, 0); int sz = pread(fd, x, 32, 0); ASSERT_EQ(sz, 32); EXPECT_NOT_POISONED(x[0]); EXPECT_NOT_POISONED(x[16]); EXPECT_NOT_POISONED(x[31]); close(fd); delete[] x; } TEST(MemorySanitizer, readv) { char buf[2011]; struct iovec iov[2]; iov[0].iov_base = buf + 1; iov[0].iov_len = 5; iov[1].iov_base = buf + 10; iov[1].iov_len = 2000; int fd = open(FILE_TO_READ, O_RDONLY); ASSERT_GT(fd, 0); int sz = readv(fd, iov, 2); ASSERT_GE(sz, 0); ASSERT_LE(sz, 5 + 2000); ASSERT_GT((size_t)sz, iov[0].iov_len); EXPECT_POISONED(buf[0]); EXPECT_NOT_POISONED(buf[1]); EXPECT_NOT_POISONED(buf[5]); EXPECT_POISONED(buf[6]); EXPECT_POISONED(buf[9]); EXPECT_NOT_POISONED(buf[10]); EXPECT_NOT_POISONED(buf[10 + (sz - 1) - 5]); EXPECT_POISONED(buf[11 + (sz - 1) - 5]); close(fd); } TEST(MemorySanitizer, preadv) { char buf[2011]; struct iovec iov[2]; iov[0].iov_base = buf + 1; iov[0].iov_len = 5; iov[1].iov_base = buf + 10; iov[1].iov_len = 2000; int fd = open(FILE_TO_READ, O_RDONLY); ASSERT_GT(fd, 0); int sz = preadv(fd, iov, 2, 3); ASSERT_GE(sz, 0); ASSERT_LE(sz, 5 + 2000); ASSERT_GT((size_t)sz, iov[0].iov_len); EXPECT_POISONED(buf[0]); EXPECT_NOT_POISONED(buf[1]); EXPECT_NOT_POISONED(buf[5]); EXPECT_POISONED(buf[6]); EXPECT_POISONED(buf[9]); EXPECT_NOT_POISONED(buf[10]); EXPECT_NOT_POISONED(buf[10 + (sz - 1) - 5]); EXPECT_POISONED(buf[11 + (sz - 1) - 5]); close(fd); } // FIXME: fails now. TEST(MemorySanitizer, DISABLED_ioctl) { struct winsize ws; EXPECT_EQ(ioctl(2, TIOCGWINSZ, &ws), 0); EXPECT_NOT_POISONED(ws.ws_col); } TEST(MemorySanitizer, readlink) { char *x = new char[1000]; readlink(SYMLINK_TO_READ, x, 1000); EXPECT_NOT_POISONED(x[0]); delete [] x; } TEST(MemorySanitizer, stat) { struct stat* st = new struct stat; int res = stat(FILE_TO_READ, st); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(st->st_dev); EXPECT_NOT_POISONED(st->st_mode); EXPECT_NOT_POISONED(st->st_size); } TEST(MemorySanitizer, fstatat) { struct stat* st = new struct stat; int dirfd = open(DIR_TO_READ, O_RDONLY); ASSERT_GT(dirfd, 0); int res = fstatat(dirfd, SUBFILE_TO_READ, st, 0); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(st->st_dev); EXPECT_NOT_POISONED(st->st_mode); EXPECT_NOT_POISONED(st->st_size); close(dirfd); } TEST(MemorySanitizer, statfs) { struct statfs st; int res = statfs("/", &st); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(st.f_type); EXPECT_NOT_POISONED(st.f_bfree); EXPECT_NOT_POISONED(st.f_namelen); } TEST(MemorySanitizer, statvfs) { struct statvfs st; int res = statvfs("/", &st); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(st.f_bsize); EXPECT_NOT_POISONED(st.f_blocks); EXPECT_NOT_POISONED(st.f_bfree); EXPECT_NOT_POISONED(st.f_namemax); } TEST(MemorySanitizer, fstatvfs) { struct statvfs st; int fd = open("/", O_RDONLY | O_DIRECTORY); int res = fstatvfs(fd, &st); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(st.f_bsize); EXPECT_NOT_POISONED(st.f_blocks); EXPECT_NOT_POISONED(st.f_bfree); EXPECT_NOT_POISONED(st.f_namemax); close(fd); } TEST(MemorySanitizer, pipe) { int* pipefd = new int[2]; int res = pipe(pipefd); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(pipefd[0]); EXPECT_NOT_POISONED(pipefd[1]); close(pipefd[0]); close(pipefd[1]); } TEST(MemorySanitizer, pipe2) { int* pipefd = new int[2]; int res = pipe2(pipefd, O_NONBLOCK); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(pipefd[0]); EXPECT_NOT_POISONED(pipefd[1]); close(pipefd[0]); close(pipefd[1]); } TEST(MemorySanitizer, socketpair) { int sv[2]; int res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(sv[0]); EXPECT_NOT_POISONED(sv[1]); close(sv[0]); close(sv[1]); } TEST(MemorySanitizer, poll) { int* pipefd = new int[2]; int res = pipe(pipefd); ASSERT_EQ(0, res); char data = 42; res = write(pipefd[1], &data, 1); ASSERT_EQ(1, res); pollfd fds[2]; fds[0].fd = pipefd[0]; fds[0].events = POLLIN; fds[1].fd = pipefd[1]; fds[1].events = POLLIN; res = poll(fds, 2, 500); ASSERT_EQ(1, res); EXPECT_NOT_POISONED(fds[0].revents); EXPECT_NOT_POISONED(fds[1].revents); close(pipefd[0]); close(pipefd[1]); } // There is no ppoll() on FreeBSD. #if !defined (__FreeBSD__) TEST(MemorySanitizer, ppoll) { int* pipefd = new int[2]; int res = pipe(pipefd); ASSERT_EQ(0, res); char data = 42; res = write(pipefd[1], &data, 1); ASSERT_EQ(1, res); pollfd fds[2]; fds[0].fd = pipefd[0]; fds[0].events = POLLIN; fds[1].fd = pipefd[1]; fds[1].events = POLLIN; sigset_t ss; sigemptyset(&ss); res = ppoll(fds, 2, NULL, &ss); ASSERT_EQ(1, res); EXPECT_NOT_POISONED(fds[0].revents); EXPECT_NOT_POISONED(fds[1].revents); close(pipefd[0]); close(pipefd[1]); } #endif TEST(MemorySanitizer, poll_positive) { int* pipefd = new int[2]; int res = pipe(pipefd); ASSERT_EQ(0, res); pollfd fds[2]; fds[0].fd = pipefd[0]; fds[0].events = POLLIN; // fds[1].fd uninitialized fds[1].events = POLLIN; EXPECT_UMR(poll(fds, 2, 0)); close(pipefd[0]); close(pipefd[1]); } TEST(MemorySanitizer, bind_getsockname) { int sock = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_in sai; memset(&sai, 0, sizeof(sai)); sai.sin_family = AF_UNIX; int res = bind(sock, (struct sockaddr *)&sai, sizeof(sai)); ASSERT_EQ(0, res); char buf[200]; socklen_t addrlen; EXPECT_UMR(getsockname(sock, (struct sockaddr *)&buf, &addrlen)); addrlen = sizeof(buf); res = getsockname(sock, (struct sockaddr *)&buf, &addrlen); EXPECT_NOT_POISONED(addrlen); EXPECT_NOT_POISONED(buf[0]); EXPECT_NOT_POISONED(buf[addrlen - 1]); EXPECT_POISONED(buf[addrlen]); close(sock); } TEST(MemorySanitizer, accept) { int listen_socket = socket(AF_INET, SOCK_STREAM, 0); ASSERT_LT(0, listen_socket); struct sockaddr_in sai; memset(&sai, 0, sizeof(sai)); sai.sin_family = AF_INET; sai.sin_port = 0; sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK); int res = bind(listen_socket, (struct sockaddr *)&sai, sizeof(sai)); ASSERT_EQ(0, res); res = listen(listen_socket, 1); ASSERT_EQ(0, res); socklen_t sz = sizeof(sai); res = getsockname(listen_socket, (struct sockaddr *)&sai, &sz); ASSERT_EQ(0, res); ASSERT_EQ(sizeof(sai), sz); int connect_socket = socket(AF_INET, SOCK_STREAM, 0); ASSERT_LT(0, connect_socket); res = fcntl(connect_socket, F_SETFL, O_NONBLOCK); ASSERT_EQ(0, res); res = connect(connect_socket, (struct sockaddr *)&sai, sizeof(sai)); // On FreeBSD this connection completes immediately. if (res != 0) { ASSERT_EQ(-1, res); ASSERT_EQ(EINPROGRESS, errno); } __msan_poison(&sai, sizeof(sai)); int new_sock = accept(listen_socket, (struct sockaddr *)&sai, &sz); ASSERT_LT(0, new_sock); ASSERT_EQ(sizeof(sai), sz); EXPECT_NOT_POISONED(sai); __msan_poison(&sai, sizeof(sai)); res = getpeername(new_sock, (struct sockaddr *)&sai, &sz); ASSERT_EQ(0, res); ASSERT_EQ(sizeof(sai), sz); EXPECT_NOT_POISONED(sai); close(new_sock); close(connect_socket); close(listen_socket); } TEST(MemorySanitizer, getaddrinfo) { struct addrinfo *ai; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; int res = getaddrinfo("localhost", NULL, &hints, &ai); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(*ai); ASSERT_EQ(sizeof(sockaddr_in), ai->ai_addrlen); EXPECT_NOT_POISONED(*(sockaddr_in*)ai->ai_addr); } TEST(MemorySanitizer, getnameinfo) { struct sockaddr_in sai; memset(&sai, 0, sizeof(sai)); sai.sin_family = AF_INET; sai.sin_port = 80; sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK); char host[500]; char serv[500]; int res = getnameinfo((struct sockaddr *)&sai, sizeof(sai), host, sizeof(host), serv, sizeof(serv), 0); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(host[0]); EXPECT_POISONED(host[sizeof(host) - 1]); ASSERT_NE(0U, strlen(host)); EXPECT_NOT_POISONED(serv[0]); EXPECT_POISONED(serv[sizeof(serv) - 1]); ASSERT_NE(0U, strlen(serv)); } #define EXPECT_HOSTENT_NOT_POISONED(he) \ do { \ EXPECT_NOT_POISONED(*(he)); \ ASSERT_NE((void *) 0, (he)->h_name); \ ASSERT_NE((void *) 0, (he)->h_aliases); \ ASSERT_NE((void *) 0, (he)->h_addr_list); \ EXPECT_NOT_POISONED(strlen((he)->h_name)); \ char **p = (he)->h_aliases; \ while (*p) { \ EXPECT_NOT_POISONED(strlen(*p)); \ ++p; \ } \ char **q = (he)->h_addr_list; \ while (*q) { \ EXPECT_NOT_POISONED(*q[0]); \ ++q; \ } \ EXPECT_NOT_POISONED(*q); \ } while (0) TEST(MemorySanitizer, gethostent) { struct hostent *he = gethostent(); ASSERT_NE((void *)NULL, he); EXPECT_HOSTENT_NOT_POISONED(he); } #ifndef MSAN_TEST_DISABLE_GETHOSTBYNAME TEST(MemorySanitizer, gethostbyname) { struct hostent *he = gethostbyname("localhost"); ASSERT_NE((void *)NULL, he); EXPECT_HOSTENT_NOT_POISONED(he); } #endif // MSAN_TEST_DISABLE_GETHOSTBYNAME TEST(MemorySanitizer, recvmsg) { int server_socket = socket(AF_INET, SOCK_DGRAM, 0); ASSERT_LT(0, server_socket); struct sockaddr_in sai; memset(&sai, 0, sizeof(sai)); sai.sin_family = AF_INET; sai.sin_port = 0; sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK); int res = bind(server_socket, (struct sockaddr *)&sai, sizeof(sai)); ASSERT_EQ(0, res); socklen_t sz = sizeof(sai); res = getsockname(server_socket, (struct sockaddr *)&sai, &sz); ASSERT_EQ(0, res); ASSERT_EQ(sizeof(sai), sz); int client_socket = socket(AF_INET, SOCK_DGRAM, 0); ASSERT_LT(0, client_socket); struct sockaddr_in client_sai; memset(&client_sai, 0, sizeof(client_sai)); client_sai.sin_family = AF_INET; client_sai.sin_port = 0; client_sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK); res = bind(client_socket, (struct sockaddr *)&client_sai, sizeof(client_sai)); ASSERT_EQ(0, res); sz = sizeof(client_sai); res = getsockname(client_socket, (struct sockaddr *)&client_sai, &sz); ASSERT_EQ(0, res); ASSERT_EQ(sizeof(client_sai), sz); const char *s = "message text"; struct iovec iov; iov.iov_base = (void *)s; iov.iov_len = strlen(s) + 1; struct msghdr msg; memset(&msg, 0, sizeof(msg)); msg.msg_name = &sai; msg.msg_namelen = sizeof(sai); msg.msg_iov = &iov; msg.msg_iovlen = 1; res = sendmsg(client_socket, &msg, 0); ASSERT_LT(0, res); char buf[1000]; struct iovec recv_iov; recv_iov.iov_base = (void *)&buf; recv_iov.iov_len = sizeof(buf); struct sockaddr_in recv_sai; struct msghdr recv_msg; memset(&recv_msg, 0, sizeof(recv_msg)); recv_msg.msg_name = &recv_sai; recv_msg.msg_namelen = sizeof(recv_sai); recv_msg.msg_iov = &recv_iov; recv_msg.msg_iovlen = 1; res = recvmsg(server_socket, &recv_msg, 0); ASSERT_LT(0, res); ASSERT_EQ(sizeof(recv_sai), recv_msg.msg_namelen); EXPECT_NOT_POISONED(*(struct sockaddr_in *)recv_msg.msg_name); EXPECT_STREQ(s, buf); close(server_socket); close(client_socket); } TEST(MemorySanitizer, gethostbyname2) { struct hostent *he = gethostbyname2("localhost", AF_INET); ASSERT_NE((void *)NULL, he); EXPECT_HOSTENT_NOT_POISONED(he); } TEST(MemorySanitizer, gethostbyaddr) { in_addr_t addr = inet_addr("127.0.0.1"); EXPECT_NOT_POISONED(addr); struct hostent *he = gethostbyaddr(&addr, sizeof(addr), AF_INET); ASSERT_NE((void *)NULL, he); EXPECT_HOSTENT_NOT_POISONED(he); } TEST(MemorySanitizer, gethostent_r) { char buf[2000]; struct hostent he; struct hostent *result; int err; int res = gethostent_r(&he, buf, sizeof(buf), &result, &err); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(result); ASSERT_NE((void *)NULL, result); EXPECT_HOSTENT_NOT_POISONED(result); EXPECT_NOT_POISONED(err); } TEST(MemorySanitizer, gethostbyname_r) { char buf[2000]; struct hostent he; struct hostent *result; int err; int res = gethostbyname_r("localhost", &he, buf, sizeof(buf), &result, &err); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(result); ASSERT_NE((void *)NULL, result); EXPECT_HOSTENT_NOT_POISONED(result); EXPECT_NOT_POISONED(err); } TEST(MemorySanitizer, gethostbyname_r_bad_host_name) { char buf[2000]; struct hostent he; struct hostent *result; int err; int res = gethostbyname_r("bad-host-name", &he, buf, sizeof(buf), &result, &err); ASSERT_EQ((struct hostent *)0, result); EXPECT_NOT_POISONED(err); } TEST(MemorySanitizer, gethostbyname_r_erange) { char buf[5]; struct hostent he; struct hostent *result; int err; int res = gethostbyname_r("localhost", &he, buf, sizeof(buf), &result, &err); ASSERT_EQ(ERANGE, res); EXPECT_NOT_POISONED(err); } TEST(MemorySanitizer, gethostbyname2_r) { char buf[2000]; struct hostent he; struct hostent *result; int err; int res = gethostbyname2_r("localhost", AF_INET, &he, buf, sizeof(buf), &result, &err); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(result); ASSERT_NE((void *)NULL, result); EXPECT_HOSTENT_NOT_POISONED(result); EXPECT_NOT_POISONED(err); } TEST(MemorySanitizer, gethostbyaddr_r) { char buf[2000]; struct hostent he; struct hostent *result; int err; in_addr_t addr = inet_addr("127.0.0.1"); EXPECT_NOT_POISONED(addr); int res = gethostbyaddr_r(&addr, sizeof(addr), AF_INET, &he, buf, sizeof(buf), &result, &err); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(result); ASSERT_NE((void *)NULL, result); EXPECT_HOSTENT_NOT_POISONED(result); EXPECT_NOT_POISONED(err); } TEST(MemorySanitizer, getsockopt) { int sock = socket(AF_UNIX, SOCK_STREAM, 0); struct linger l[2]; socklen_t sz = sizeof(l[0]); int res = getsockopt(sock, SOL_SOCKET, SO_LINGER, &l[0], &sz); ASSERT_EQ(0, res); ASSERT_EQ(sizeof(l[0]), sz); EXPECT_NOT_POISONED(l[0]); EXPECT_POISONED(*(char *)(l + 1)); } TEST(MemorySanitizer, getcwd) { char path[PATH_MAX + 1]; char* res = getcwd(path, sizeof(path)); ASSERT_TRUE(res != NULL); EXPECT_NOT_POISONED(path[0]); } TEST(MemorySanitizer, getcwd_gnu) { char* res = getcwd(NULL, 0); ASSERT_TRUE(res != NULL); EXPECT_NOT_POISONED(res[0]); free(res); } // There's no get_current_dir_name() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, get_current_dir_name) { char* res = get_current_dir_name(); ASSERT_TRUE(res != NULL); EXPECT_NOT_POISONED(res[0]); free(res); } #endif TEST(MemorySanitizer, shmctl) { int id = shmget(IPC_PRIVATE, 4096, 0644 | IPC_CREAT); ASSERT_GT(id, -1); struct shmid_ds ds; int res = shmctl(id, IPC_STAT, &ds); ASSERT_GT(res, -1); EXPECT_NOT_POISONED(ds); // FreeBSD does not support shmctl(IPC_INFO) and shmctl(SHM_INFO). #if !defined(__FreeBSD__) struct shminfo si; res = shmctl(id, IPC_INFO, (struct shmid_ds *)&si); ASSERT_GT(res, -1); EXPECT_NOT_POISONED(si); struct shm_info s_i; res = shmctl(id, SHM_INFO, (struct shmid_ds *)&s_i); ASSERT_GT(res, -1); EXPECT_NOT_POISONED(s_i); #endif res = shmctl(id, IPC_RMID, 0); ASSERT_GT(res, -1); } TEST(MemorySanitizer, shmat) { void *p = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_NE(MAP_FAILED, p); ((char *)p)[10] = *GetPoisoned(); ((char *)p)[4095] = *GetPoisoned(); int res = munmap(p, 4096); ASSERT_EQ(0, res); int id = shmget(IPC_PRIVATE, 4096, 0644 | IPC_CREAT); ASSERT_GT(id, -1); void *q = shmat(id, p, 0); ASSERT_EQ(p, q); EXPECT_NOT_POISONED(((char *)q)[0]); EXPECT_NOT_POISONED(((char *)q)[10]); EXPECT_NOT_POISONED(((char *)q)[4095]); res = shmdt(q); ASSERT_EQ(0, res); res = shmctl(id, IPC_RMID, 0); ASSERT_GT(res, -1); } // There's no random_r() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, random_r) { int32_t x; char z[64]; memset(z, 0, sizeof(z)); struct random_data buf; memset(&buf, 0, sizeof(buf)); int res = initstate_r(0, z, sizeof(z), &buf); ASSERT_EQ(0, res); res = random_r(&buf, &x); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(x); } #endif TEST(MemorySanitizer, confstr) { char buf[3]; size_t res = confstr(_CS_PATH, buf, sizeof(buf)); ASSERT_GT(res, sizeof(buf)); EXPECT_NOT_POISONED(buf[0]); EXPECT_NOT_POISONED(buf[sizeof(buf) - 1]); char buf2[1000]; res = confstr(_CS_PATH, buf2, sizeof(buf2)); ASSERT_LT(res, sizeof(buf2)); EXPECT_NOT_POISONED(buf2[0]); EXPECT_NOT_POISONED(buf2[res - 1]); EXPECT_POISONED(buf2[res]); ASSERT_EQ(res, strlen(buf2) + 1); } TEST(MemorySanitizer, opendir) { DIR *dir = opendir("."); closedir(dir); char name[10] = "."; __msan_poison(name, sizeof(name)); EXPECT_UMR(dir = opendir(name)); closedir(dir); } TEST(MemorySanitizer, readdir) { DIR *dir = opendir("."); struct dirent *d = readdir(dir); ASSERT_TRUE(d != NULL); EXPECT_NOT_POISONED(d->d_name[0]); closedir(dir); } TEST(MemorySanitizer, readdir_r) { DIR *dir = opendir("."); struct dirent d; struct dirent *pd; int res = readdir_r(dir, &d, &pd); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(pd); EXPECT_NOT_POISONED(d.d_name[0]); closedir(dir); } TEST(MemorySanitizer, realpath) { const char* relpath = "."; char path[PATH_MAX + 1]; char* res = realpath(relpath, path); ASSERT_TRUE(res != NULL); EXPECT_NOT_POISONED(path[0]); } TEST(MemorySanitizer, realpath_null) { const char* relpath = "."; char* res = realpath(relpath, NULL); printf("%d, %s\n", errno, strerror(errno)); ASSERT_TRUE(res != NULL); EXPECT_NOT_POISONED(res[0]); free(res); } // There's no canonicalize_file_name() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, canonicalize_file_name) { const char* relpath = "."; char* res = canonicalize_file_name(relpath); ASSERT_TRUE(res != NULL); EXPECT_NOT_POISONED(res[0]); free(res); } #endif extern char **environ; TEST(MemorySanitizer, setenv) { setenv("AAA", "BBB", 1); for (char **envp = environ; *envp; ++envp) { EXPECT_NOT_POISONED(*envp); EXPECT_NOT_POISONED(*envp[0]); } } TEST(MemorySanitizer, putenv) { char s[] = "AAA=BBB"; putenv(s); for (char **envp = environ; *envp; ++envp) { EXPECT_NOT_POISONED(*envp); EXPECT_NOT_POISONED(*envp[0]); } } TEST(MemorySanitizer, memcpy) { char* x = new char[2]; char* y = new char[2]; x[0] = 1; x[1] = *GetPoisoned(); memcpy(y, x, 2); EXPECT_NOT_POISONED(y[0]); EXPECT_POISONED(y[1]); } void TestUnalignedMemcpy(unsigned left, unsigned right, bool src_is_aligned, bool src_is_poisoned, bool dst_is_poisoned) { fprintf(stderr, "%s(%d, %d, %d, %d, %d)\n", __func__, left, right, src_is_aligned, src_is_poisoned, dst_is_poisoned); const unsigned sz = 20; U4 dst_origin, src_origin; char *dst = (char *)malloc(sz); if (dst_is_poisoned) dst_origin = __msan_get_origin(dst); else memset(dst, 0, sz); char *src = (char *)malloc(sz); if (src_is_poisoned) src_origin = __msan_get_origin(src); else memset(src, 0, sz); memcpy(dst + left, src_is_aligned ? src + left : src, sz - left - right); for (unsigned i = 0; i < (left & (~3U)); ++i) if (dst_is_poisoned) EXPECT_POISONED_O(dst[i], dst_origin); else EXPECT_NOT_POISONED(dst[i]); for (unsigned i = 0; i < (right & (~3U)); ++i) if (dst_is_poisoned) EXPECT_POISONED_O(dst[sz - i - 1], dst_origin); else EXPECT_NOT_POISONED(dst[sz - i - 1]); for (unsigned i = left; i < sz - right; ++i) if (src_is_poisoned) EXPECT_POISONED_O(dst[i], src_origin); else EXPECT_NOT_POISONED(dst[i]); free(dst); free(src); } TEST(MemorySanitizer, memcpy_unaligned) { for (int i = 0; i < 10; ++i) for (int j = 0; j < 10; ++j) for (int aligned = 0; aligned < 2; ++aligned) for (int srcp = 0; srcp < 2; ++srcp) for (int dstp = 0; dstp < 2; ++dstp) TestUnalignedMemcpy(i, j, aligned, srcp, dstp); } TEST(MemorySanitizer, memmove) { char* x = new char[2]; char* y = new char[2]; x[0] = 1; x[1] = *GetPoisoned(); memmove(y, x, 2); EXPECT_NOT_POISONED(y[0]); EXPECT_POISONED(y[1]); } TEST(MemorySanitizer, memccpy_nomatch) { char* x = new char[5]; char* y = new char[5]; strcpy(x, "abc"); memccpy(y, x, 'd', 4); EXPECT_NOT_POISONED(y[0]); EXPECT_NOT_POISONED(y[1]); EXPECT_NOT_POISONED(y[2]); EXPECT_NOT_POISONED(y[3]); EXPECT_POISONED(y[4]); delete[] x; delete[] y; } TEST(MemorySanitizer, memccpy_match) { char* x = new char[5]; char* y = new char[5]; strcpy(x, "abc"); memccpy(y, x, 'b', 4); EXPECT_NOT_POISONED(y[0]); EXPECT_NOT_POISONED(y[1]); EXPECT_POISONED(y[2]); EXPECT_POISONED(y[3]); EXPECT_POISONED(y[4]); delete[] x; delete[] y; } TEST(MemorySanitizer, memccpy_nomatch_positive) { char* x = new char[5]; char* y = new char[5]; strcpy(x, "abc"); EXPECT_UMR(memccpy(y, x, 'd', 5)); delete[] x; delete[] y; } TEST(MemorySanitizer, memccpy_match_positive) { char* x = new char[5]; char* y = new char[5]; x[0] = 'a'; x[2] = 'b'; EXPECT_UMR(memccpy(y, x, 'b', 5)); delete[] x; delete[] y; } TEST(MemorySanitizer, bcopy) { char* x = new char[2]; char* y = new char[2]; x[0] = 1; x[1] = *GetPoisoned(); bcopy(x, y, 2); EXPECT_NOT_POISONED(y[0]); EXPECT_POISONED(y[1]); } TEST(MemorySanitizer, strdup) { char buf[4] = "abc"; __msan_poison(buf + 2, sizeof(*buf)); char *x = strdup(buf); EXPECT_NOT_POISONED(x[0]); EXPECT_NOT_POISONED(x[1]); EXPECT_POISONED(x[2]); EXPECT_NOT_POISONED(x[3]); free(x); } TEST(MemorySanitizer, strndup) { char buf[4] = "abc"; __msan_poison(buf + 2, sizeof(*buf)); char *x = strndup(buf, 3); EXPECT_NOT_POISONED(x[0]); EXPECT_NOT_POISONED(x[1]); EXPECT_POISONED(x[2]); EXPECT_NOT_POISONED(x[3]); free(x); } TEST(MemorySanitizer, strndup_short) { char buf[4] = "abc"; __msan_poison(buf + 1, sizeof(*buf)); __msan_poison(buf + 2, sizeof(*buf)); char *x = strndup(buf, 2); EXPECT_NOT_POISONED(x[0]); EXPECT_POISONED(x[1]); EXPECT_NOT_POISONED(x[2]); free(x); } template void TestOverlapMemmove() { T *x = new T[size]; ASSERT_GE(size, 3); x[2] = 0; memmove(x, x + 1, (size - 1) * sizeof(T)); EXPECT_NOT_POISONED(x[1]); EXPECT_POISONED(x[0]); EXPECT_POISONED(x[2]); delete [] x; } TEST(MemorySanitizer, overlap_memmove) { TestOverlapMemmove(); TestOverlapMemmove(); TestOverlapMemmove(); TestOverlapMemmove(); } TEST(MemorySanitizer, strcpy) { // NOLINT char* x = new char[3]; char* y = new char[3]; x[0] = 'a'; x[1] = *GetPoisoned(1, 1); x[2] = 0; strcpy(y, x); // NOLINT EXPECT_NOT_POISONED(y[0]); EXPECT_POISONED(y[1]); EXPECT_NOT_POISONED(y[2]); } TEST(MemorySanitizer, strncpy) { // NOLINT char* x = new char[3]; char* y = new char[5]; x[0] = 'a'; x[1] = *GetPoisoned(1, 1); x[2] = '\0'; strncpy(y, x, 4); // NOLINT EXPECT_NOT_POISONED(y[0]); EXPECT_POISONED(y[1]); EXPECT_NOT_POISONED(y[2]); EXPECT_NOT_POISONED(y[3]); EXPECT_POISONED(y[4]); } TEST(MemorySanitizer, stpcpy) { // NOLINT char* x = new char[3]; char* y = new char[3]; x[0] = 'a'; x[1] = *GetPoisoned(1, 1); x[2] = 0; char *res = stpcpy(y, x); // NOLINT ASSERT_EQ(res, y + 2); EXPECT_NOT_POISONED(y[0]); EXPECT_POISONED(y[1]); EXPECT_NOT_POISONED(y[2]); } TEST(MemorySanitizer, strcat) { // NOLINT char a[10]; char b[] = "def"; strcpy(a, "abc"); __msan_poison(b + 1, 1); strcat(a, b); EXPECT_NOT_POISONED(a[3]); EXPECT_POISONED(a[4]); EXPECT_NOT_POISONED(a[5]); EXPECT_NOT_POISONED(a[6]); EXPECT_POISONED(a[7]); } TEST(MemorySanitizer, strncat) { // NOLINT char a[10]; char b[] = "def"; strcpy(a, "abc"); __msan_poison(b + 1, 1); strncat(a, b, 5); EXPECT_NOT_POISONED(a[3]); EXPECT_POISONED(a[4]); EXPECT_NOT_POISONED(a[5]); EXPECT_NOT_POISONED(a[6]); EXPECT_POISONED(a[7]); } TEST(MemorySanitizer, strncat_overflow) { // NOLINT char a[10]; char b[] = "def"; strcpy(a, "abc"); __msan_poison(b + 1, 1); strncat(a, b, 2); EXPECT_NOT_POISONED(a[3]); EXPECT_POISONED(a[4]); EXPECT_NOT_POISONED(a[5]); EXPECT_POISONED(a[6]); EXPECT_POISONED(a[7]); } #define TEST_STRTO_INT(func_name, char_type, str_prefix) \ TEST(MemorySanitizer, func_name) { \ char_type *e; \ EXPECT_EQ(1U, func_name(str_prefix##"1", &e, 10)); \ EXPECT_NOT_POISONED((S8)e); \ } #define TEST_STRTO_FLOAT(func_name, char_type, str_prefix) \ TEST(MemorySanitizer, func_name) { \ char_type *e; \ EXPECT_NE(0, func_name(str_prefix##"1.5", &e)); \ EXPECT_NOT_POISONED((S8)e); \ } #define TEST_STRTO_FLOAT_LOC(func_name, char_type, str_prefix) \ TEST(MemorySanitizer, func_name) { \ locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); \ char_type *e; \ EXPECT_NE(0, func_name(str_prefix##"1.5", &e, loc)); \ EXPECT_NOT_POISONED((S8)e); \ freelocale(loc); \ } #define TEST_STRTO_INT_LOC(func_name, char_type, str_prefix) \ TEST(MemorySanitizer, func_name) { \ locale_t loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); \ char_type *e; \ ASSERT_EQ(1U, func_name(str_prefix##"1", &e, 10, loc)); \ EXPECT_NOT_POISONED((S8)e); \ freelocale(loc); \ } TEST_STRTO_INT(strtol, char, ) TEST_STRTO_INT(strtoll, char, ) TEST_STRTO_INT(strtoul, char, ) TEST_STRTO_INT(strtoull, char, ) TEST_STRTO_FLOAT(strtof, char, ) TEST_STRTO_FLOAT(strtod, char, ) TEST_STRTO_FLOAT(strtold, char, ) TEST_STRTO_FLOAT_LOC(strtof_l, char, ) TEST_STRTO_FLOAT_LOC(strtod_l, char, ) TEST_STRTO_FLOAT_LOC(strtold_l, char, ) TEST_STRTO_INT_LOC(strtol_l, char, ) TEST_STRTO_INT_LOC(strtoll_l, char, ) TEST_STRTO_INT_LOC(strtoul_l, char, ) TEST_STRTO_INT_LOC(strtoull_l, char, ) TEST_STRTO_INT(wcstol, wchar_t, L) TEST_STRTO_INT(wcstoll, wchar_t, L) TEST_STRTO_INT(wcstoul, wchar_t, L) TEST_STRTO_INT(wcstoull, wchar_t, L) TEST_STRTO_FLOAT(wcstof, wchar_t, L) TEST_STRTO_FLOAT(wcstod, wchar_t, L) TEST_STRTO_FLOAT(wcstold, wchar_t, L) TEST_STRTO_FLOAT_LOC(wcstof_l, wchar_t, L) TEST_STRTO_FLOAT_LOC(wcstod_l, wchar_t, L) TEST_STRTO_FLOAT_LOC(wcstold_l, wchar_t, L) TEST_STRTO_INT_LOC(wcstol_l, wchar_t, L) TEST_STRTO_INT_LOC(wcstoll_l, wchar_t, L) TEST_STRTO_INT_LOC(wcstoul_l, wchar_t, L) TEST_STRTO_INT_LOC(wcstoull_l, wchar_t, L) TEST(MemorySanitizer, strtoimax) { char *e; ASSERT_EQ(1, strtoimax("1", &e, 10)); EXPECT_NOT_POISONED((S8) e); } TEST(MemorySanitizer, strtoumax) { char *e; ASSERT_EQ(1U, strtoumax("1", &e, 10)); EXPECT_NOT_POISONED((S8) e); } #ifdef __GLIBC__ extern "C" float __strtof_l(const char *nptr, char **endptr, locale_t loc); TEST_STRTO_FLOAT_LOC(__strtof_l, char, ) extern "C" double __strtod_l(const char *nptr, char **endptr, locale_t loc); TEST_STRTO_FLOAT_LOC(__strtod_l, char, ) extern "C" long double __strtold_l(const char *nptr, char **endptr, locale_t loc); TEST_STRTO_FLOAT_LOC(__strtold_l, char, ) extern "C" float __wcstof_l(const wchar_t *nptr, wchar_t **endptr, locale_t loc); TEST_STRTO_FLOAT_LOC(__wcstof_l, wchar_t, L) extern "C" double __wcstod_l(const wchar_t *nptr, wchar_t **endptr, locale_t loc); TEST_STRTO_FLOAT_LOC(__wcstod_l, wchar_t, L) extern "C" long double __wcstold_l(const wchar_t *nptr, wchar_t **endptr, locale_t loc); TEST_STRTO_FLOAT_LOC(__wcstold_l, wchar_t, L) #endif // __GLIBC__ TEST(MemorySanitizer, modf) { double x, y; x = modf(2.1, &y); EXPECT_NOT_POISONED(y); } TEST(MemorySanitizer, modff) { float x, y; x = modff(2.1, &y); EXPECT_NOT_POISONED(y); } TEST(MemorySanitizer, modfl) { long double x, y; x = modfl(2.1, &y); EXPECT_NOT_POISONED(y); } // There's no sincos() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, sincos) { double s, c; sincos(0.2, &s, &c); EXPECT_NOT_POISONED(s); EXPECT_NOT_POISONED(c); } #endif // There's no sincosf() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, sincosf) { float s, c; sincosf(0.2, &s, &c); EXPECT_NOT_POISONED(s); EXPECT_NOT_POISONED(c); } #endif // There's no sincosl() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, sincosl) { long double s, c; sincosl(0.2, &s, &c); EXPECT_NOT_POISONED(s); EXPECT_NOT_POISONED(c); } #endif TEST(MemorySanitizer, remquo) { int quo; double res = remquo(29.0, 3.0, &quo); ASSERT_NE(0.0, res); EXPECT_NOT_POISONED(quo); } TEST(MemorySanitizer, remquof) { int quo; float res = remquof(29.0, 3.0, &quo); ASSERT_NE(0.0, res); EXPECT_NOT_POISONED(quo); } TEST(MemorySanitizer, remquol) { int quo; long double res = remquof(29.0, 3.0, &quo); ASSERT_NE(0.0, res); EXPECT_NOT_POISONED(quo); } TEST(MemorySanitizer, lgamma) { double res = lgamma(1.1); ASSERT_NE(0.0, res); EXPECT_NOT_POISONED(signgam); } TEST(MemorySanitizer, lgammaf) { float res = lgammaf(1.1); ASSERT_NE(0.0, res); EXPECT_NOT_POISONED(signgam); } TEST(MemorySanitizer, lgammal) { long double res = lgammal(1.1); ASSERT_NE(0.0, res); EXPECT_NOT_POISONED(signgam); } TEST(MemorySanitizer, lgamma_r) { int sgn; double res = lgamma_r(1.1, &sgn); ASSERT_NE(0.0, res); EXPECT_NOT_POISONED(sgn); } TEST(MemorySanitizer, lgammaf_r) { int sgn; float res = lgammaf_r(1.1, &sgn); ASSERT_NE(0.0, res); EXPECT_NOT_POISONED(sgn); } // There's no lgammal_r() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, lgammal_r) { int sgn; long double res = lgammal_r(1.1, &sgn); ASSERT_NE(0.0, res); EXPECT_NOT_POISONED(sgn); } #endif // There's no drand48_r() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, drand48_r) { struct drand48_data buf; srand48_r(0, &buf); double d; drand48_r(&buf, &d); EXPECT_NOT_POISONED(d); } #endif // There's no lrand48_r() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, lrand48_r) { struct drand48_data buf; srand48_r(0, &buf); long d; lrand48_r(&buf, &d); EXPECT_NOT_POISONED(d); } #endif TEST(MemorySanitizer, sprintf) { // NOLINT char buff[10]; break_optimization(buff); EXPECT_POISONED(buff[0]); int res = sprintf(buff, "%d", 1234567); // NOLINT ASSERT_EQ(res, 7); ASSERT_EQ(buff[0], '1'); ASSERT_EQ(buff[1], '2'); ASSERT_EQ(buff[2], '3'); ASSERT_EQ(buff[6], '7'); ASSERT_EQ(buff[7], 0); EXPECT_POISONED(buff[8]); } TEST(MemorySanitizer, snprintf) { char buff[10]; break_optimization(buff); EXPECT_POISONED(buff[0]); int res = snprintf(buff, sizeof(buff), "%d", 1234567); ASSERT_EQ(res, 7); ASSERT_EQ(buff[0], '1'); ASSERT_EQ(buff[1], '2'); ASSERT_EQ(buff[2], '3'); ASSERT_EQ(buff[6], '7'); ASSERT_EQ(buff[7], 0); EXPECT_POISONED(buff[8]); } TEST(MemorySanitizer, swprintf) { wchar_t buff[10]; ASSERT_EQ(4U, sizeof(wchar_t)); break_optimization(buff); EXPECT_POISONED(buff[0]); int res = swprintf(buff, 9, L"%d", 1234567); ASSERT_EQ(res, 7); ASSERT_EQ(buff[0], '1'); ASSERT_EQ(buff[1], '2'); ASSERT_EQ(buff[2], '3'); ASSERT_EQ(buff[6], '7'); ASSERT_EQ(buff[7], 0); EXPECT_POISONED(buff[8]); } TEST(MemorySanitizer, asprintf) { // NOLINT char *pbuf; EXPECT_POISONED(pbuf); int res = asprintf(&pbuf, "%d", 1234567); // NOLINT ASSERT_EQ(res, 7); EXPECT_NOT_POISONED(pbuf); ASSERT_EQ(pbuf[0], '1'); ASSERT_EQ(pbuf[1], '2'); ASSERT_EQ(pbuf[2], '3'); ASSERT_EQ(pbuf[6], '7'); ASSERT_EQ(pbuf[7], 0); free(pbuf); } TEST(MemorySanitizer, mbstowcs) { const char *x = "abc"; wchar_t buff[10]; int res = mbstowcs(buff, x, 2); EXPECT_EQ(2, res); EXPECT_EQ(L'a', buff[0]); EXPECT_EQ(L'b', buff[1]); EXPECT_POISONED(buff[2]); res = mbstowcs(buff, x, 10); EXPECT_EQ(3, res); EXPECT_NOT_POISONED(buff[3]); } TEST(MemorySanitizer, wcstombs) { const wchar_t *x = L"abc"; char buff[10]; int res = wcstombs(buff, x, 4); EXPECT_EQ(res, 3); EXPECT_EQ(buff[0], 'a'); EXPECT_EQ(buff[1], 'b'); EXPECT_EQ(buff[2], 'c'); } TEST(MemorySanitizer, wcsrtombs) { const wchar_t *x = L"abc"; const wchar_t *p = x; char buff[10]; mbstate_t mbs; memset(&mbs, 0, sizeof(mbs)); int res = wcsrtombs(buff, &p, 4, &mbs); EXPECT_EQ(res, 3); EXPECT_EQ(buff[0], 'a'); EXPECT_EQ(buff[1], 'b'); EXPECT_EQ(buff[2], 'c'); EXPECT_EQ(buff[3], '\0'); EXPECT_POISONED(buff[4]); } TEST(MemorySanitizer, wcsnrtombs) { const wchar_t *x = L"abc"; const wchar_t *p = x; char buff[10]; mbstate_t mbs; memset(&mbs, 0, sizeof(mbs)); int res = wcsnrtombs(buff, &p, 2, 4, &mbs); EXPECT_EQ(res, 2); EXPECT_EQ(buff[0], 'a'); EXPECT_EQ(buff[1], 'b'); EXPECT_POISONED(buff[2]); } TEST(MemorySanitizer, wmemset) { wchar_t x[25]; break_optimization(x); EXPECT_POISONED(x[0]); wmemset(x, L'A', 10); EXPECT_EQ(x[0], L'A'); EXPECT_EQ(x[9], L'A'); EXPECT_POISONED(x[10]); } TEST(MemorySanitizer, mbtowc) { const char *x = "abc"; wchar_t wx; int res = mbtowc(&wx, x, 3); EXPECT_GT(res, 0); EXPECT_NOT_POISONED(wx); } TEST(MemorySanitizer, mbrtowc) { const char *x = "abc"; wchar_t wx; mbstate_t mbs; memset(&mbs, 0, sizeof(mbs)); int res = mbrtowc(&wx, x, 3, &mbs); EXPECT_GT(res, 0); EXPECT_NOT_POISONED(wx); } TEST(MemorySanitizer, wcsftime) { wchar_t x[100]; time_t t = time(NULL); struct tm tms; struct tm *tmres = localtime_r(&t, &tms); ASSERT_NE((void *)0, tmres); size_t res = wcsftime(x, sizeof(x) / sizeof(x[0]), L"%Y-%m-%d", tmres); EXPECT_GT(res, 0UL); EXPECT_EQ(res, wcslen(x)); } TEST(MemorySanitizer, gettimeofday) { struct timeval tv; struct timezone tz; break_optimization(&tv); break_optimization(&tz); ASSERT_EQ(16U, sizeof(tv)); ASSERT_EQ(8U, sizeof(tz)); EXPECT_POISONED(tv.tv_sec); EXPECT_POISONED(tv.tv_usec); EXPECT_POISONED(tz.tz_minuteswest); EXPECT_POISONED(tz.tz_dsttime); ASSERT_EQ(0, gettimeofday(&tv, &tz)); EXPECT_NOT_POISONED(tv.tv_sec); EXPECT_NOT_POISONED(tv.tv_usec); EXPECT_NOT_POISONED(tz.tz_minuteswest); EXPECT_NOT_POISONED(tz.tz_dsttime); } TEST(MemorySanitizer, clock_gettime) { struct timespec tp; EXPECT_POISONED(tp.tv_sec); EXPECT_POISONED(tp.tv_nsec); ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &tp)); EXPECT_NOT_POISONED(tp.tv_sec); EXPECT_NOT_POISONED(tp.tv_nsec); } TEST(MemorySanitizer, clock_getres) { struct timespec tp; EXPECT_POISONED(tp.tv_sec); EXPECT_POISONED(tp.tv_nsec); ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, 0)); EXPECT_POISONED(tp.tv_sec); EXPECT_POISONED(tp.tv_nsec); ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, &tp)); EXPECT_NOT_POISONED(tp.tv_sec); EXPECT_NOT_POISONED(tp.tv_nsec); } TEST(MemorySanitizer, getitimer) { struct itimerval it1, it2; int res; EXPECT_POISONED(it1.it_interval.tv_sec); EXPECT_POISONED(it1.it_interval.tv_usec); EXPECT_POISONED(it1.it_value.tv_sec); EXPECT_POISONED(it1.it_value.tv_usec); res = getitimer(ITIMER_VIRTUAL, &it1); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(it1.it_interval.tv_sec); EXPECT_NOT_POISONED(it1.it_interval.tv_usec); EXPECT_NOT_POISONED(it1.it_value.tv_sec); EXPECT_NOT_POISONED(it1.it_value.tv_usec); it1.it_interval.tv_sec = it1.it_value.tv_sec = 10000; it1.it_interval.tv_usec = it1.it_value.tv_usec = 0; res = setitimer(ITIMER_VIRTUAL, &it1, &it2); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(it2.it_interval.tv_sec); EXPECT_NOT_POISONED(it2.it_interval.tv_usec); EXPECT_NOT_POISONED(it2.it_value.tv_sec); EXPECT_NOT_POISONED(it2.it_value.tv_usec); // Check that old_value can be 0, and disable the timer. memset(&it1, 0, sizeof(it1)); res = setitimer(ITIMER_VIRTUAL, &it1, 0); ASSERT_EQ(0, res); } TEST(MemorySanitizer, setitimer_null) { setitimer(ITIMER_VIRTUAL, 0, 0); // Not testing the return value, since it the behaviour seems to differ // between libc implementations and POSIX. // Should never crash, though. } TEST(MemorySanitizer, time) { time_t t; EXPECT_POISONED(t); time_t t2 = time(&t); ASSERT_NE(t2, (time_t)-1); EXPECT_NOT_POISONED(t); } TEST(MemorySanitizer, strptime) { struct tm time; char *p = strptime("11/1/2013-05:39", "%m/%d/%Y-%H:%M", &time); ASSERT_TRUE(p != NULL); EXPECT_NOT_POISONED(time.tm_sec); EXPECT_NOT_POISONED(time.tm_hour); EXPECT_NOT_POISONED(time.tm_year); } TEST(MemorySanitizer, localtime) { time_t t = 123; struct tm *time = localtime(&t); ASSERT_TRUE(time != NULL); EXPECT_NOT_POISONED(time->tm_sec); EXPECT_NOT_POISONED(time->tm_hour); EXPECT_NOT_POISONED(time->tm_year); EXPECT_NOT_POISONED(time->tm_isdst); EXPECT_NE(0U, strlen(time->tm_zone)); } TEST(MemorySanitizer, localtime_r) { time_t t = 123; struct tm time; struct tm *res = localtime_r(&t, &time); ASSERT_TRUE(res != NULL); EXPECT_NOT_POISONED(time.tm_sec); EXPECT_NOT_POISONED(time.tm_hour); EXPECT_NOT_POISONED(time.tm_year); EXPECT_NOT_POISONED(time.tm_isdst); EXPECT_NE(0U, strlen(time.tm_zone)); } // There's no getmntent() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, getmntent) { FILE *fp = setmntent("/etc/fstab", "r"); struct mntent *mnt = getmntent(fp); ASSERT_TRUE(mnt != NULL); ASSERT_NE(0U, strlen(mnt->mnt_fsname)); ASSERT_NE(0U, strlen(mnt->mnt_dir)); ASSERT_NE(0U, strlen(mnt->mnt_type)); ASSERT_NE(0U, strlen(mnt->mnt_opts)); EXPECT_NOT_POISONED(mnt->mnt_freq); EXPECT_NOT_POISONED(mnt->mnt_passno); fclose(fp); } #endif // There's no getmntent_r() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, getmntent_r) { FILE *fp = setmntent("/etc/fstab", "r"); struct mntent mntbuf; char buf[1000]; struct mntent *mnt = getmntent_r(fp, &mntbuf, buf, sizeof(buf)); ASSERT_TRUE(mnt != NULL); ASSERT_NE(0U, strlen(mnt->mnt_fsname)); ASSERT_NE(0U, strlen(mnt->mnt_dir)); ASSERT_NE(0U, strlen(mnt->mnt_type)); ASSERT_NE(0U, strlen(mnt->mnt_opts)); EXPECT_NOT_POISONED(mnt->mnt_freq); EXPECT_NOT_POISONED(mnt->mnt_passno); fclose(fp); } #endif TEST(MemorySanitizer, ether) { const char *asc = "11:22:33:44:55:66"; struct ether_addr *paddr = ether_aton(asc); EXPECT_NOT_POISONED(*paddr); struct ether_addr addr; paddr = ether_aton_r(asc, &addr); ASSERT_EQ(paddr, &addr); EXPECT_NOT_POISONED(addr); char *s = ether_ntoa(&addr); ASSERT_NE(0U, strlen(s)); char buf[100]; s = ether_ntoa_r(&addr, buf); ASSERT_EQ(s, buf); ASSERT_NE(0U, strlen(buf)); } TEST(MemorySanitizer, mmap) { const int size = 4096; void *p1, *p2; p1 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); __msan_poison(p1, size); munmap(p1, size); for (int i = 0; i < 1000; i++) { p2 = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); if (p2 == p1) break; else munmap(p2, size); } if (p1 == p2) { EXPECT_NOT_POISONED(*(char*)p2); munmap(p2, size); } } +// There's no fcvt() on FreeBSD. +#if !defined(__FreeBSD__) // FIXME: enable and add ecvt. // FIXME: check why msandr does nt handle fcvt. TEST(MemorySanitizer, fcvt) { int a, b; break_optimization(&a); break_optimization(&b); EXPECT_POISONED(a); EXPECT_POISONED(b); char *str = fcvt(12345.6789, 10, &a, &b); EXPECT_NOT_POISONED(a); EXPECT_NOT_POISONED(b); ASSERT_NE(nullptr, str); EXPECT_NOT_POISONED(str[0]); ASSERT_NE(0U, strlen(str)); } +#endif +// There's no fcvt_long() on FreeBSD. +#if !defined(__FreeBSD__) TEST(MemorySanitizer, fcvt_long) { int a, b; break_optimization(&a); break_optimization(&b); EXPECT_POISONED(a); EXPECT_POISONED(b); char *str = fcvt(111111112345.6789, 10, &a, &b); EXPECT_NOT_POISONED(a); EXPECT_NOT_POISONED(b); ASSERT_NE(nullptr, str); EXPECT_NOT_POISONED(str[0]); ASSERT_NE(0U, strlen(str)); } +#endif - TEST(MemorySanitizer, memchr) { char x[10]; break_optimization(x); EXPECT_POISONED(x[0]); x[2] = '2'; void *res; EXPECT_UMR(res = memchr(x, '2', 10)); EXPECT_NOT_POISONED(res); x[0] = '0'; x[1] = '1'; res = memchr(x, '2', 10); EXPECT_EQ(&x[2], res); EXPECT_UMR(res = memchr(x, '3', 10)); EXPECT_NOT_POISONED(res); } TEST(MemorySanitizer, memrchr) { char x[10]; break_optimization(x); EXPECT_POISONED(x[0]); x[9] = '9'; void *res; EXPECT_UMR(res = memrchr(x, '9', 10)); EXPECT_NOT_POISONED(res); x[0] = '0'; x[1] = '1'; res = memrchr(x, '0', 2); EXPECT_EQ(&x[0], res); EXPECT_UMR(res = memrchr(x, '7', 10)); EXPECT_NOT_POISONED(res); } TEST(MemorySanitizer, frexp) { int x; x = *GetPoisoned(); double r = frexp(1.1, &x); EXPECT_NOT_POISONED(r); EXPECT_NOT_POISONED(x); x = *GetPoisoned(); float rf = frexpf(1.1, &x); EXPECT_NOT_POISONED(rf); EXPECT_NOT_POISONED(x); x = *GetPoisoned(); double rl = frexpl(1.1, &x); EXPECT_NOT_POISONED(rl); EXPECT_NOT_POISONED(x); } namespace { static int cnt; void SigactionHandler(int signo, siginfo_t* si, void* uc) { ASSERT_EQ(signo, SIGPROF); ASSERT_TRUE(si != NULL); EXPECT_NOT_POISONED(si->si_errno); EXPECT_NOT_POISONED(si->si_pid); #if __linux__ # if defined(__x86_64__) EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_RIP]); # elif defined(__i386__) EXPECT_NOT_POISONED(((ucontext_t*)uc)->uc_mcontext.gregs[REG_EIP]); # endif #endif ++cnt; } TEST(MemorySanitizer, sigaction) { struct sigaction act = {}; struct sigaction oldact = {}; struct sigaction origact = {}; sigaction(SIGPROF, 0, &origact); act.sa_flags |= SA_SIGINFO; act.sa_sigaction = &SigactionHandler; sigaction(SIGPROF, &act, 0); kill(getpid(), SIGPROF); act.sa_flags &= ~SA_SIGINFO; act.sa_handler = SIG_DFL; sigaction(SIGPROF, &act, 0); act.sa_flags &= ~SA_SIGINFO; act.sa_handler = SIG_IGN; sigaction(SIGPROF, &act, &oldact); EXPECT_FALSE(oldact.sa_flags & SA_SIGINFO); EXPECT_EQ(SIG_DFL, oldact.sa_handler); kill(getpid(), SIGPROF); act.sa_flags |= SA_SIGINFO; act.sa_sigaction = &SigactionHandler; sigaction(SIGPROF, &act, &oldact); EXPECT_FALSE(oldact.sa_flags & SA_SIGINFO); EXPECT_EQ(SIG_IGN, oldact.sa_handler); kill(getpid(), SIGPROF); act.sa_flags &= ~SA_SIGINFO; act.sa_handler = SIG_DFL; sigaction(SIGPROF, &act, &oldact); EXPECT_TRUE(oldact.sa_flags & SA_SIGINFO); EXPECT_EQ(&SigactionHandler, oldact.sa_sigaction); EXPECT_EQ(2, cnt); sigaction(SIGPROF, &origact, 0); } } // namespace TEST(MemorySanitizer, sigemptyset) { sigset_t s; EXPECT_POISONED(s); int res = sigemptyset(&s); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(s); } TEST(MemorySanitizer, sigfillset) { sigset_t s; EXPECT_POISONED(s); int res = sigfillset(&s); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(s); } TEST(MemorySanitizer, sigpending) { sigset_t s; EXPECT_POISONED(s); int res = sigpending(&s); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(s); } TEST(MemorySanitizer, sigprocmask) { sigset_t s; EXPECT_POISONED(s); int res = sigprocmask(SIG_BLOCK, 0, &s); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(s); } struct StructWithDtor { ~StructWithDtor(); }; NOINLINE StructWithDtor::~StructWithDtor() { break_optimization(0); } TEST(MemorySanitizer, Invoke) { StructWithDtor s; // Will cause the calls to become invokes. EXPECT_NOT_POISONED(0); EXPECT_POISONED(*GetPoisoned()); EXPECT_NOT_POISONED(0); EXPECT_POISONED(*GetPoisoned()); EXPECT_POISONED(ReturnPoisoned()); } TEST(MemorySanitizer, ptrtoint) { // Test that shadow is propagated through pointer-to-integer conversion. void* p = (void*)0xABCD; __msan_poison(((char*)&p) + 1, sizeof(p)); EXPECT_NOT_POISONED((((uintptr_t)p) & 0xFF) == 0); void* q = (void*)0xABCD; __msan_poison(&q, sizeof(q) - 1); EXPECT_POISONED((((uintptr_t)q) & 0xFF) == 0); } static void vaargsfn2(int guard, ...) { va_list vl; va_start(vl, guard); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_POISONED(va_arg(vl, double)); va_end(vl); } static void vaargsfn(int guard, ...) { va_list vl; va_start(vl, guard); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_POISONED(va_arg(vl, int)); // The following call will overwrite __msan_param_tls. // Checks after it test that arg shadow was somehow saved across the call. vaargsfn2(1, 2, 3, 4, *GetPoisoned()); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_POISONED(va_arg(vl, int)); va_end(vl); } TEST(MemorySanitizer, VAArgTest) { int* x = GetPoisoned(); int* y = GetPoisoned(4); vaargsfn(1, 13, *x, 42, *y); } static void vaargsfn_many(int guard, ...) { va_list vl; va_start(vl, guard); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_POISONED(va_arg(vl, int)); va_end(vl); } TEST(MemorySanitizer, VAArgManyTest) { int* x = GetPoisoned(); int* y = GetPoisoned(4); vaargsfn_many(1, 2, *x, 3, 4, 5, 6, 7, 8, 9, *y); } static void vaargsfn_pass2(va_list vl) { EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_POISONED(va_arg(vl, int)); } static void vaargsfn_pass(int guard, ...) { va_list vl; va_start(vl, guard); EXPECT_POISONED(va_arg(vl, int)); vaargsfn_pass2(vl); va_end(vl); } TEST(MemorySanitizer, VAArgPass) { int* x = GetPoisoned(); int* y = GetPoisoned(4); vaargsfn_pass(1, *x, 2, 3, *y); } static void vaargsfn_copy2(va_list vl) { EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_POISONED(va_arg(vl, int)); } static void vaargsfn_copy(int guard, ...) { va_list vl; va_start(vl, guard); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_POISONED(va_arg(vl, int)); va_list vl2; va_copy(vl2, vl); vaargsfn_copy2(vl2); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_POISONED(va_arg(vl, int)); va_end(vl); } TEST(MemorySanitizer, VAArgCopy) { int* x = GetPoisoned(); int* y = GetPoisoned(4); vaargsfn_copy(1, 2, *x, 3, *y); } static void vaargsfn_ptr(int guard, ...) { va_list vl; va_start(vl, guard); EXPECT_NOT_POISONED(va_arg(vl, int*)); EXPECT_POISONED(va_arg(vl, int*)); EXPECT_NOT_POISONED(va_arg(vl, int*)); EXPECT_POISONED(va_arg(vl, double*)); va_end(vl); } TEST(MemorySanitizer, VAArgPtr) { int** x = GetPoisoned(); double** y = GetPoisoned(8); int z; vaargsfn_ptr(1, &z, *x, &z, *y); } static void vaargsfn_overflow(int guard, ...) { va_list vl; va_start(vl, guard); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, double)); EXPECT_NOT_POISONED(va_arg(vl, double)); EXPECT_NOT_POISONED(va_arg(vl, double)); EXPECT_POISONED(va_arg(vl, double)); EXPECT_NOT_POISONED(va_arg(vl, double)); EXPECT_POISONED(va_arg(vl, int*)); EXPECT_NOT_POISONED(va_arg(vl, double)); EXPECT_NOT_POISONED(va_arg(vl, double)); EXPECT_POISONED(va_arg(vl, int)); EXPECT_POISONED(va_arg(vl, double)); EXPECT_POISONED(va_arg(vl, int*)); EXPECT_NOT_POISONED(va_arg(vl, int)); EXPECT_NOT_POISONED(va_arg(vl, double)); EXPECT_NOT_POISONED(va_arg(vl, int*)); EXPECT_POISONED(va_arg(vl, int)); EXPECT_POISONED(va_arg(vl, double)); EXPECT_POISONED(va_arg(vl, int*)); va_end(vl); } TEST(MemorySanitizer, VAArgOverflow) { int* x = GetPoisoned(); double* y = GetPoisoned(8); int** p = GetPoisoned(16); int z; vaargsfn_overflow(1, 1, 2, *x, 4, 5, 6, 1.1, 2.2, 3.3, *y, 5.5, *p, 7.7, 8.8, // the following args will overflow for sure *x, *y, *p, 7, 9.9, &z, *x, *y, *p); } static void vaargsfn_tlsoverwrite2(int guard, ...) { va_list vl; va_start(vl, guard); for (int i = 0; i < 20; ++i) EXPECT_NOT_POISONED(va_arg(vl, int)); va_end(vl); } static void vaargsfn_tlsoverwrite(int guard, ...) { // This call will overwrite TLS contents unless it's backed up somewhere. vaargsfn_tlsoverwrite2(2, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42); // 20x va_list vl; va_start(vl, guard); for (int i = 0; i < 20; ++i) EXPECT_POISONED(va_arg(vl, int)); va_end(vl); } TEST(MemorySanitizer, VAArgTLSOverwrite) { int* x = GetPoisoned(); vaargsfn_tlsoverwrite(1, *x, *x, *x, *x, *x, *x, *x, *x, *x, *x, *x, *x, *x, *x, *x, *x, *x, *x, *x, *x); // 20x } struct StructByVal { int a, b, c, d, e, f; }; static void vaargsfn_structbyval(int guard, ...) { va_list vl; va_start(vl, guard); { StructByVal s = va_arg(vl, StructByVal); EXPECT_NOT_POISONED(s.a); EXPECT_POISONED(s.b); EXPECT_NOT_POISONED(s.c); EXPECT_POISONED(s.d); EXPECT_NOT_POISONED(s.e); EXPECT_POISONED(s.f); } { StructByVal s = va_arg(vl, StructByVal); EXPECT_NOT_POISONED(s.a); EXPECT_POISONED(s.b); EXPECT_NOT_POISONED(s.c); EXPECT_POISONED(s.d); EXPECT_NOT_POISONED(s.e); EXPECT_POISONED(s.f); } va_end(vl); } TEST(MemorySanitizer, VAArgStructByVal) { StructByVal s; s.a = 1; s.b = *GetPoisoned(); s.c = 2; s.d = *GetPoisoned(); s.e = 3; s.f = *GetPoisoned(); vaargsfn_structbyval(0, s, s); } NOINLINE void StructByValTestFunc(struct StructByVal s) { EXPECT_NOT_POISONED(s.a); EXPECT_POISONED(s.b); EXPECT_NOT_POISONED(s.c); EXPECT_POISONED(s.d); EXPECT_NOT_POISONED(s.e); EXPECT_POISONED(s.f); } NOINLINE void StructByValTestFunc1(struct StructByVal s) { StructByValTestFunc(s); } NOINLINE void StructByValTestFunc2(int z, struct StructByVal s) { StructByValTestFunc(s); } TEST(MemorySanitizer, StructByVal) { // Large aggregates are passed as "byval" pointer argument in LLVM. struct StructByVal s; s.a = 1; s.b = *GetPoisoned(); s.c = 2; s.d = *GetPoisoned(); s.e = 3; s.f = *GetPoisoned(); StructByValTestFunc(s); StructByValTestFunc1(s); StructByValTestFunc2(0, s); } #if MSAN_HAS_M128 NOINLINE __m128i m128Eq(__m128i *a, __m128i *b) { return _mm_cmpeq_epi16(*a, *b); } NOINLINE __m128i m128Lt(__m128i *a, __m128i *b) { return _mm_cmplt_epi16(*a, *b); } TEST(MemorySanitizer, m128) { __m128i a = _mm_set1_epi16(0x1234); __m128i b = _mm_set1_epi16(0x7890); EXPECT_NOT_POISONED(m128Eq(&a, &b)); EXPECT_NOT_POISONED(m128Lt(&a, &b)); } // FIXME: add more tests for __m128i. #endif // MSAN_HAS_M128 // We should not complain when copying this poisoned hole. struct StructWithHole { U4 a; // 4-byte hole. U8 b; }; NOINLINE StructWithHole ReturnStructWithHole() { StructWithHole res; __msan_poison(&res, sizeof(res)); res.a = 1; res.b = 2; return res; } TEST(MemorySanitizer, StructWithHole) { StructWithHole a = ReturnStructWithHole(); break_optimization(&a); } template NOINLINE T ReturnStruct() { T res; __msan_poison(&res, sizeof(res)); res.a = 1; return res; } template NOINLINE void TestReturnStruct() { T s1 = ReturnStruct(); EXPECT_NOT_POISONED(s1.a); EXPECT_POISONED(s1.b); } struct SSS1 { int a, b, c; }; struct SSS2 { int b, a, c; }; struct SSS3 { int b, c, a; }; struct SSS4 { int c, b, a; }; struct SSS5 { int a; float b; }; struct SSS6 { int a; double b; }; struct SSS7 { S8 b; int a; }; struct SSS8 { S2 b; S8 a; }; TEST(MemorySanitizer, IntStruct3) { TestReturnStruct(); TestReturnStruct(); TestReturnStruct(); TestReturnStruct(); TestReturnStruct(); TestReturnStruct(); TestReturnStruct(); TestReturnStruct(); } struct LongStruct { U1 a1, b1; U2 a2, b2; U4 a4, b4; U8 a8, b8; }; NOINLINE LongStruct ReturnLongStruct1() { LongStruct res; __msan_poison(&res, sizeof(res)); res.a1 = res.a2 = res.a4 = res.a8 = 111; // leaves b1, .., b8 poisoned. return res; } NOINLINE LongStruct ReturnLongStruct2() { LongStruct res; __msan_poison(&res, sizeof(res)); res.b1 = res.b2 = res.b4 = res.b8 = 111; // leaves a1, .., a8 poisoned. return res; } TEST(MemorySanitizer, LongStruct) { LongStruct s1 = ReturnLongStruct1(); __msan_print_shadow(&s1, sizeof(s1)); EXPECT_NOT_POISONED(s1.a1); EXPECT_NOT_POISONED(s1.a2); EXPECT_NOT_POISONED(s1.a4); EXPECT_NOT_POISONED(s1.a8); EXPECT_POISONED(s1.b1); EXPECT_POISONED(s1.b2); EXPECT_POISONED(s1.b4); EXPECT_POISONED(s1.b8); LongStruct s2 = ReturnLongStruct2(); __msan_print_shadow(&s2, sizeof(s2)); EXPECT_NOT_POISONED(s2.b1); EXPECT_NOT_POISONED(s2.b2); EXPECT_NOT_POISONED(s2.b4); EXPECT_NOT_POISONED(s2.b8); EXPECT_POISONED(s2.a1); EXPECT_POISONED(s2.a2); EXPECT_POISONED(s2.a4); EXPECT_POISONED(s2.a8); } TEST(MemorySanitizer, getrlimit) { struct rlimit limit; __msan_poison(&limit, sizeof(limit)); int result = getrlimit(RLIMIT_DATA, &limit); ASSERT_EQ(result, 0); EXPECT_NOT_POISONED(limit.rlim_cur); EXPECT_NOT_POISONED(limit.rlim_max); } TEST(MemorySanitizer, getrusage) { struct rusage usage; __msan_poison(&usage, sizeof(usage)); int result = getrusage(RUSAGE_SELF, &usage); ASSERT_EQ(result, 0); EXPECT_NOT_POISONED(usage.ru_utime.tv_sec); EXPECT_NOT_POISONED(usage.ru_utime.tv_usec); EXPECT_NOT_POISONED(usage.ru_stime.tv_sec); EXPECT_NOT_POISONED(usage.ru_stime.tv_usec); EXPECT_NOT_POISONED(usage.ru_maxrss); EXPECT_NOT_POISONED(usage.ru_minflt); EXPECT_NOT_POISONED(usage.ru_majflt); EXPECT_NOT_POISONED(usage.ru_inblock); EXPECT_NOT_POISONED(usage.ru_oublock); EXPECT_NOT_POISONED(usage.ru_nvcsw); EXPECT_NOT_POISONED(usage.ru_nivcsw); } -#ifdef __GLIBC__ -extern char *program_invocation_name; -#else // __GLIBC__ +#if defined(__FreeBSD__) +static void GetProgramPath(char *buf, size_t sz) { + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + int res = sysctl(mib, 4, buf, &sz, NULL, 0); + ASSERT_EQ(0, res); +} +#elif defined(__GLIBC__) +static void GetProgramPath(char *buf, size_t sz) { + extern char *program_invocation_name; + int res = snprintf(buf, sz, "%s", program_invocation_name); + ASSERT_GE(res, 0); + ASSERT_LT((size_t)res, sz); +} +#else # error "TODO: port this" #endif static void dladdr_testfn() {} TEST(MemorySanitizer, dladdr) { Dl_info info; __msan_poison(&info, sizeof(info)); int result = dladdr((const void*)dladdr_testfn, &info); ASSERT_NE(result, 0); EXPECT_NOT_POISONED((unsigned long)info.dli_fname); if (info.dli_fname) EXPECT_NOT_POISONED(strlen(info.dli_fname)); EXPECT_NOT_POISONED((unsigned long)info.dli_fbase); EXPECT_NOT_POISONED((unsigned long)info.dli_sname); if (info.dli_sname) EXPECT_NOT_POISONED(strlen(info.dli_sname)); EXPECT_NOT_POISONED((unsigned long)info.dli_saddr); } #ifndef MSAN_TEST_DISABLE_DLOPEN static int dl_phdr_callback(struct dl_phdr_info *info, size_t size, void *data) { (*(int *)data)++; EXPECT_NOT_POISONED(info->dlpi_addr); EXPECT_NOT_POISONED(strlen(info->dlpi_name)); EXPECT_NOT_POISONED(info->dlpi_phnum); for (int i = 0; i < info->dlpi_phnum; ++i) EXPECT_NOT_POISONED(info->dlpi_phdr[i]); return 0; } // Compute the path to our loadable DSO. We assume it's in the same // directory. Only use string routines that we intercept so far to do this. -static int PathToLoadable(char *buf, size_t sz) { - const char *basename = "libmsan_loadable.x86_64.so"; - char *argv0 = program_invocation_name; - char *last_slash = strrchr(argv0, '/'); - assert(last_slash); - int res = - snprintf(buf, sz, "%.*s/%s", int(last_slash - argv0), argv0, basename); - assert(res >= 0); - return (size_t)res < sz ? 0 : res; +static void GetPathToLoadable(char *buf, size_t sz) { + char program_path[kMaxPathLength]; + GetProgramPath(program_path, sizeof(program_path)); + + const char *last_slash = strrchr(program_path, '/'); + ASSERT_NE(nullptr, last_slash); + size_t dir_len = (size_t)(last_slash - program_path); +#if defined(__x86_64__) + static const char basename[] = "libmsan_loadable.x86_64.so"; +#elif defined(__MIPSEB__) || defined(MIPSEB) + static const char basename[] = "libmsan_loadable.mips64.so"; +#elif defined(__mips64) + static const char basename[] = "libmsan_loadable.mips64el.so"; +#endif + int res = snprintf(buf, sz, "%.*s/%s", + (int)dir_len, program_path, basename); + ASSERT_GE(res, 0); + ASSERT_LT((size_t)res, sz); } TEST(MemorySanitizer, dl_iterate_phdr) { - char path[4096]; - int res = PathToLoadable(path, sizeof(path)); - ASSERT_EQ(0, res); + char path[kMaxPathLength]; + GetPathToLoadable(path, sizeof(path)); // Having at least one dlopen'ed library in the process makes this more // entertaining. void *lib = dlopen(path, RTLD_LAZY); ASSERT_NE((void*)0, lib); int count = 0; int result = dl_iterate_phdr(dl_phdr_callback, &count); ASSERT_GT(count, 0); - + dlclose(lib); } - TEST(MemorySanitizer, dlopen) { - char path[4096]; - int res = PathToLoadable(path, sizeof(path)); - ASSERT_EQ(0, res); + char path[kMaxPathLength]; + GetPathToLoadable(path, sizeof(path)); // We need to clear shadow for globals when doing dlopen. In order to test // this, we have to poison the shadow for the DSO before we load it. In // general this is difficult, but the loader tends to reload things in the // same place, so we open, close, and then reopen. The global should always // start out clean after dlopen. for (int i = 0; i < 2; i++) { void *lib = dlopen(path, RTLD_LAZY); if (lib == NULL) { printf("dlerror: %s\n", dlerror()); ASSERT_TRUE(lib != NULL); } void **(*get_dso_global)() = (void **(*)())dlsym(lib, "get_dso_global"); ASSERT_TRUE(get_dso_global != NULL); void **dso_global = get_dso_global(); EXPECT_NOT_POISONED(*dso_global); __msan_poison(dso_global, sizeof(*dso_global)); EXPECT_POISONED(*dso_global); dlclose(lib); } } // Regression test for a crash in dlopen() interceptor. TEST(MemorySanitizer, dlopenFailed) { - const char *path = "/libmsan_loadable_does_not_exist.x86_64.so"; + const char *path = "/libmsan_loadable_does_not_exist.so"; void *lib = dlopen(path, RTLD_LAZY); ASSERT_TRUE(lib == NULL); } #endif // MSAN_TEST_DISABLE_DLOPEN // There's no sched_getaffinity() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, sched_getaffinity) { cpu_set_t mask; int res = sched_getaffinity(getpid(), sizeof(mask), &mask); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(mask); } #endif TEST(MemorySanitizer, scanf) { const char *input = "42 hello"; int* d = new int; char* s = new char[7]; int res = sscanf(input, "%d %5s", d, s); printf("res %d\n", res); ASSERT_EQ(res, 2); EXPECT_NOT_POISONED(*d); EXPECT_NOT_POISONED(s[0]); EXPECT_NOT_POISONED(s[1]); EXPECT_NOT_POISONED(s[2]); EXPECT_NOT_POISONED(s[3]); EXPECT_NOT_POISONED(s[4]); EXPECT_NOT_POISONED(s[5]); EXPECT_POISONED(s[6]); delete[] s; delete d; } static void *SimpleThread_threadfn(void* data) { return new int; } TEST(MemorySanitizer, SimpleThread) { pthread_t t; void *p; int res = pthread_create(&t, NULL, SimpleThread_threadfn, NULL); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(t); res = pthread_join(t, &p); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(p); delete (int*)p; } static void *SmallStackThread_threadfn(void* data) { return 0; } TEST(MemorySanitizer, SmallStackThread) { pthread_attr_t attr; pthread_t t; void *p; int res; res = pthread_attr_init(&attr); ASSERT_EQ(0, res); res = pthread_attr_setstacksize(&attr, 64 * 1024); ASSERT_EQ(0, res); res = pthread_create(&t, &attr, SmallStackThread_threadfn, NULL); ASSERT_EQ(0, res); res = pthread_join(t, &p); ASSERT_EQ(0, res); res = pthread_attr_destroy(&attr); ASSERT_EQ(0, res); } TEST(MemorySanitizer, SmallPreAllocatedStackThread) { pthread_attr_t attr; pthread_t t; int res; res = pthread_attr_init(&attr); ASSERT_EQ(0, res); void *stack; const size_t kStackSize = 16 * 1024; res = posix_memalign(&stack, 4096, kStackSize); ASSERT_EQ(0, res); res = pthread_attr_setstack(&attr, stack, kStackSize); ASSERT_EQ(0, res); res = pthread_create(&t, &attr, SmallStackThread_threadfn, NULL); EXPECT_EQ(0, res); res = pthread_join(t, NULL); ASSERT_EQ(0, res); res = pthread_attr_destroy(&attr); ASSERT_EQ(0, res); } TEST(MemorySanitizer, pthread_attr_get) { pthread_attr_t attr; int res; res = pthread_attr_init(&attr); ASSERT_EQ(0, res); { int v; res = pthread_attr_getdetachstate(&attr, &v); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(v); } { size_t v; res = pthread_attr_getguardsize(&attr, &v); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(v); } { struct sched_param v; res = pthread_attr_getschedparam(&attr, &v); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(v); } { int v; res = pthread_attr_getschedpolicy(&attr, &v); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(v); } { int v; res = pthread_attr_getinheritsched(&attr, &v); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(v); } { int v; res = pthread_attr_getscope(&attr, &v); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(v); } { size_t v; res = pthread_attr_getstacksize(&attr, &v); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(v); } { void *v; size_t w; res = pthread_attr_getstack(&attr, &v, &w); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(v); EXPECT_NOT_POISONED(w); } { cpu_set_t v; res = pthread_attr_getaffinity_np(&attr, sizeof(v), &v); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(v); } res = pthread_attr_destroy(&attr); ASSERT_EQ(0, res); } TEST(MemorySanitizer, pthread_getschedparam) { int policy; struct sched_param param; int res = pthread_getschedparam(pthread_self(), &policy, ¶m); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(policy); EXPECT_NOT_POISONED(param.sched_priority); } TEST(MemorySanitizer, pthread_key_create) { pthread_key_t key; int res = pthread_key_create(&key, NULL); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(key); res = pthread_key_delete(key); ASSERT_EQ(0, res); } namespace { struct SignalCondArg { pthread_cond_t* cond; pthread_mutex_t* mu; bool broadcast; }; void *SignalCond(void *param) { SignalCondArg *arg = reinterpret_cast(param); pthread_mutex_lock(arg->mu); if (arg->broadcast) pthread_cond_broadcast(arg->cond); else pthread_cond_signal(arg->cond); pthread_mutex_unlock(arg->mu); return 0; } } // namespace TEST(MemorySanitizer, pthread_cond_wait) { pthread_cond_t cond; pthread_mutex_t mu; SignalCondArg args = {&cond, &mu, false}; pthread_cond_init(&cond, 0); pthread_mutex_init(&mu, 0); pthread_mutex_lock(&mu); // signal pthread_t thr; pthread_create(&thr, 0, SignalCond, &args); int res = pthread_cond_wait(&cond, &mu); ASSERT_EQ(0, res); pthread_join(thr, 0); // broadcast args.broadcast = true; pthread_create(&thr, 0, SignalCond, &args); res = pthread_cond_wait(&cond, &mu); ASSERT_EQ(0, res); pthread_join(thr, 0); pthread_mutex_unlock(&mu); pthread_mutex_destroy(&mu); pthread_cond_destroy(&cond); } TEST(MemorySanitizer, tmpnam) { char s[L_tmpnam]; char *res = tmpnam(s); ASSERT_EQ(s, res); EXPECT_NOT_POISONED(strlen(res)); } TEST(MemorySanitizer, tempnam) { char *res = tempnam(NULL, "zzz"); EXPECT_NOT_POISONED(strlen(res)); free(res); } TEST(MemorySanitizer, posix_memalign) { void *p; EXPECT_POISONED(p); int res = posix_memalign(&p, 4096, 13); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(p); EXPECT_EQ(0U, (uintptr_t)p % 4096); free(p); } // There's no memalign() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, memalign) { void *p = memalign(4096, 13); EXPECT_EQ(0U, (uintptr_t)p % kPageSize); free(p); } #endif TEST(MemorySanitizer, valloc) { void *a = valloc(100); EXPECT_EQ(0U, (uintptr_t)a % kPageSize); free(a); } // There's no pvalloc() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, pvalloc) { void *p = pvalloc(kPageSize + 100); EXPECT_EQ(0U, (uintptr_t)p % kPageSize); EXPECT_EQ(2 * kPageSize, __sanitizer_get_allocated_size(p)); free(p); p = pvalloc(0); // pvalloc(0) should allocate at least one page. EXPECT_EQ(0U, (uintptr_t)p % kPageSize); EXPECT_EQ(kPageSize, __sanitizer_get_allocated_size(p)); free(p); } #endif TEST(MemorySanitizer, inet_pton) { const char *s = "1:0:0:0:0:0:0:8"; unsigned char buf[sizeof(struct in6_addr)]; int res = inet_pton(AF_INET6, s, buf); ASSERT_EQ(1, res); EXPECT_NOT_POISONED(buf[0]); EXPECT_NOT_POISONED(buf[sizeof(struct in6_addr) - 1]); char s_out[INET6_ADDRSTRLEN]; EXPECT_POISONED(s_out[3]); const char *q = inet_ntop(AF_INET6, buf, s_out, INET6_ADDRSTRLEN); ASSERT_NE((void*)0, q); EXPECT_NOT_POISONED(s_out[3]); } TEST(MemorySanitizer, inet_aton) { const char *s = "127.0.0.1"; struct in_addr in[2]; int res = inet_aton(s, in); ASSERT_NE(0, res); EXPECT_NOT_POISONED(in[0]); EXPECT_POISONED(*(char *)(in + 1)); } TEST(MemorySanitizer, uname) { struct utsname u; int res = uname(&u); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(strlen(u.sysname)); EXPECT_NOT_POISONED(strlen(u.nodename)); EXPECT_NOT_POISONED(strlen(u.release)); EXPECT_NOT_POISONED(strlen(u.version)); EXPECT_NOT_POISONED(strlen(u.machine)); } TEST(MemorySanitizer, gethostname) { char buf[100]; int res = gethostname(buf, 100); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(strlen(buf)); } // There's no sysinfo() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, sysinfo) { struct sysinfo info; int res = sysinfo(&info); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(info); } #endif TEST(MemorySanitizer, getpwuid) { struct passwd *p = getpwuid(0); // root ASSERT_TRUE(p != NULL); EXPECT_NOT_POISONED(p->pw_name); ASSERT_TRUE(p->pw_name != NULL); EXPECT_NOT_POISONED(p->pw_name[0]); EXPECT_NOT_POISONED(p->pw_uid); ASSERT_EQ(0U, p->pw_uid); } TEST(MemorySanitizer, getpwuid_r) { struct passwd pwd; struct passwd *pwdres; char buf[10000]; int res = getpwuid_r(0, &pwd, buf, sizeof(buf), &pwdres); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(pwd.pw_name); ASSERT_TRUE(pwd.pw_name != NULL); EXPECT_NOT_POISONED(pwd.pw_name[0]); EXPECT_NOT_POISONED(pwd.pw_uid); ASSERT_EQ(0U, pwd.pw_uid); EXPECT_NOT_POISONED(pwdres); } TEST(MemorySanitizer, getpwnam_r) { struct passwd pwd; struct passwd *pwdres; char buf[10000]; int res = getpwnam_r("root", &pwd, buf, sizeof(buf), &pwdres); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(pwd.pw_name); ASSERT_TRUE(pwd.pw_name != NULL); EXPECT_NOT_POISONED(pwd.pw_name[0]); EXPECT_NOT_POISONED(pwd.pw_uid); ASSERT_EQ(0U, pwd.pw_uid); EXPECT_NOT_POISONED(pwdres); } TEST(MemorySanitizer, getpwnam_r_positive) { struct passwd pwd; struct passwd *pwdres; char s[5]; strncpy(s, "abcd", 5); __msan_poison(s, 5); char buf[10000]; int res; EXPECT_UMR(res = getpwnam_r(s, &pwd, buf, sizeof(buf), &pwdres)); } TEST(MemorySanitizer, getgrnam_r) { struct group grp; struct group *grpres; char buf[10000]; - int res = getgrnam_r("root", &grp, buf, sizeof(buf), &grpres); + int res = getgrnam_r(SUPERUSER_GROUP, &grp, buf, sizeof(buf), &grpres); ASSERT_EQ(0, res); + // Note that getgrnam_r() returns 0 if the matching group is not found. + ASSERT_NE(nullptr, grpres); EXPECT_NOT_POISONED(grp.gr_name); ASSERT_TRUE(grp.gr_name != NULL); EXPECT_NOT_POISONED(grp.gr_name[0]); EXPECT_NOT_POISONED(grp.gr_gid); EXPECT_NOT_POISONED(grpres); } TEST(MemorySanitizer, getpwent) { setpwent(); struct passwd *p = getpwent(); ASSERT_TRUE(p != NULL); EXPECT_NOT_POISONED(p->pw_name); ASSERT_TRUE(p->pw_name != NULL); EXPECT_NOT_POISONED(p->pw_name[0]); EXPECT_NOT_POISONED(p->pw_uid); } TEST(MemorySanitizer, getpwent_r) { struct passwd pwd; struct passwd *pwdres; char buf[10000]; setpwent(); int res = getpwent_r(&pwd, buf, sizeof(buf), &pwdres); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(pwd.pw_name); ASSERT_TRUE(pwd.pw_name != NULL); EXPECT_NOT_POISONED(pwd.pw_name[0]); EXPECT_NOT_POISONED(pwd.pw_uid); EXPECT_NOT_POISONED(pwdres); } // There's no fgetpwent() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, fgetpwent) { FILE *fp = fopen("/etc/passwd", "r"); struct passwd *p = fgetpwent(fp); ASSERT_TRUE(p != NULL); EXPECT_NOT_POISONED(p->pw_name); ASSERT_TRUE(p->pw_name != NULL); EXPECT_NOT_POISONED(p->pw_name[0]); EXPECT_NOT_POISONED(p->pw_uid); fclose(fp); } #endif TEST(MemorySanitizer, getgrent) { setgrent(); struct group *p = getgrent(); ASSERT_TRUE(p != NULL); EXPECT_NOT_POISONED(p->gr_name); ASSERT_TRUE(p->gr_name != NULL); EXPECT_NOT_POISONED(p->gr_name[0]); EXPECT_NOT_POISONED(p->gr_gid); } // There's no fgetgrent() on FreeBSD. #if !defined(__FreeBSD__) TEST(MemorySanitizer, fgetgrent) { FILE *fp = fopen("/etc/group", "r"); struct group *grp = fgetgrent(fp); ASSERT_TRUE(grp != NULL); EXPECT_NOT_POISONED(grp->gr_name); ASSERT_TRUE(grp->gr_name != NULL); EXPECT_NOT_POISONED(grp->gr_name[0]); EXPECT_NOT_POISONED(grp->gr_gid); for (char **p = grp->gr_mem; *p; ++p) { EXPECT_NOT_POISONED((*p)[0]); EXPECT_TRUE(strlen(*p) > 0); } fclose(fp); } #endif TEST(MemorySanitizer, getgrent_r) { struct group grp; struct group *grpres; char buf[10000]; setgrent(); int res = getgrent_r(&grp, buf, sizeof(buf), &grpres); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(grp.gr_name); ASSERT_TRUE(grp.gr_name != NULL); EXPECT_NOT_POISONED(grp.gr_name[0]); EXPECT_NOT_POISONED(grp.gr_gid); EXPECT_NOT_POISONED(grpres); } +// There's no fgetgrent_r() on FreeBSD. +#if !defined(__FreeBSD__) TEST(MemorySanitizer, fgetgrent_r) { FILE *fp = fopen("/etc/group", "r"); struct group grp; struct group *grpres; char buf[10000]; setgrent(); int res = fgetgrent_r(fp, &grp, buf, sizeof(buf), &grpres); ASSERT_EQ(0, res); EXPECT_NOT_POISONED(grp.gr_name); ASSERT_TRUE(grp.gr_name != NULL); EXPECT_NOT_POISONED(grp.gr_name[0]); EXPECT_NOT_POISONED(grp.gr_gid); EXPECT_NOT_POISONED(grpres); fclose(fp); } +#endif TEST(MemorySanitizer, getgroups) { int n = getgroups(0, 0); gid_t *gids = new gid_t[n]; int res = getgroups(n, gids); ASSERT_EQ(n, res); for (int i = 0; i < n; ++i) EXPECT_NOT_POISONED(gids[i]); } TEST(MemorySanitizer, wordexp) { wordexp_t w; int res = wordexp("a b c", &w, 0); ASSERT_EQ(0, res); ASSERT_EQ(3U, w.we_wordc); ASSERT_STREQ("a", w.we_wordv[0]); ASSERT_STREQ("b", w.we_wordv[1]); ASSERT_STREQ("c", w.we_wordv[2]); } template static bool applySlt(T value, T shadow) { __msan_partial_poison(&value, &shadow, sizeof(T)); volatile bool zzz = true; // This "|| zzz" trick somehow makes LLVM emit "icmp slt" instead of // a shift-and-trunc to get at the highest bit. volatile bool v = value < 0 || zzz; return v; } TEST(MemorySanitizer, SignedCompareWithZero) { EXPECT_NOT_POISONED(applySlt(0xF, 0xF)); EXPECT_NOT_POISONED(applySlt(0xF, 0xFF)); EXPECT_NOT_POISONED(applySlt(0xF, 0xFFFFFF)); EXPECT_NOT_POISONED(applySlt(0xF, 0x7FFFFFF)); EXPECT_UMR(applySlt(0xF, 0x80FFFFFF)); EXPECT_UMR(applySlt(0xF, 0xFFFFFFFF)); } template static T poisoned(T Va, S Sa) { char SIZE_CHECK1[(ssize_t)sizeof(T) - (ssize_t)sizeof(S)]; char SIZE_CHECK2[(ssize_t)sizeof(S) - (ssize_t)sizeof(T)]; T a; a = Va; __msan_partial_poison(&a, &Sa, sizeof(T)); return a; } TEST(MemorySanitizer, ICmpRelational) { EXPECT_NOT_POISONED(poisoned(0, 0) < poisoned(0, 0)); EXPECT_NOT_POISONED(poisoned(0U, 0) < poisoned(0U, 0)); EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) < poisoned(0LL, 0LLU)); EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) < poisoned(0LLU, 0LLU)); EXPECT_POISONED(poisoned(0xFF, 0xFF) < poisoned(0xFF, 0xFF)); EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) < poisoned(0xFFFFFFFFU, 0xFFFFFFFFU)); EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) < poisoned(-1, 0xFFFFFFFFU)); EXPECT_NOT_POISONED(poisoned(0, 0) <= poisoned(0, 0)); EXPECT_NOT_POISONED(poisoned(0U, 0) <= poisoned(0U, 0)); EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) <= poisoned(0LL, 0LLU)); EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) <= poisoned(0LLU, 0LLU)); EXPECT_POISONED(poisoned(0xFF, 0xFF) <= poisoned(0xFF, 0xFF)); EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) <= poisoned(0xFFFFFFFFU, 0xFFFFFFFFU)); EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) <= poisoned(-1, 0xFFFFFFFFU)); EXPECT_NOT_POISONED(poisoned(0, 0) > poisoned(0, 0)); EXPECT_NOT_POISONED(poisoned(0U, 0) > poisoned(0U, 0)); EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) > poisoned(0LL, 0LLU)); EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) > poisoned(0LLU, 0LLU)); EXPECT_POISONED(poisoned(0xFF, 0xFF) > poisoned(0xFF, 0xFF)); EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) > poisoned(0xFFFFFFFFU, 0xFFFFFFFFU)); EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) > poisoned(-1, 0xFFFFFFFFU)); EXPECT_NOT_POISONED(poisoned(0, 0) >= poisoned(0, 0)); EXPECT_NOT_POISONED(poisoned(0U, 0) >= poisoned(0U, 0)); EXPECT_NOT_POISONED(poisoned(0LL, 0LLU) >= poisoned(0LL, 0LLU)); EXPECT_NOT_POISONED(poisoned(0LLU, 0LLU) >= poisoned(0LLU, 0LLU)); EXPECT_POISONED(poisoned(0xFF, 0xFF) >= poisoned(0xFF, 0xFF)); EXPECT_POISONED(poisoned(0xFFFFFFFFU, 0xFFFFFFFFU) >= poisoned(0xFFFFFFFFU, 0xFFFFFFFFU)); EXPECT_POISONED(poisoned(-1, 0xFFFFFFFFU) >= poisoned(-1, 0xFFFFFFFFU)); EXPECT_POISONED(poisoned(6, 0xF) > poisoned(7, 0)); EXPECT_POISONED(poisoned(0xF, 0xF) > poisoned(7, 0)); EXPECT_NOT_POISONED(poisoned(-1, 0x80000000U) >= poisoned(-1, 0U)); } #if MSAN_HAS_M128 TEST(MemorySanitizer, ICmpVectorRelational) { EXPECT_NOT_POISONED( _mm_cmplt_epi16(poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0)), poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0)))); EXPECT_NOT_POISONED( _mm_cmplt_epi16(poisoned(_mm_set1_epi32(0), _mm_set1_epi32(0)), poisoned(_mm_set1_epi32(0), _mm_set1_epi32(0)))); EXPECT_POISONED( _mm_cmplt_epi16(poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0xFFFF)), poisoned(_mm_set1_epi16(0), _mm_set1_epi16(0xFFFF)))); EXPECT_POISONED(_mm_cmpgt_epi16(poisoned(_mm_set1_epi16(6), _mm_set1_epi16(0xF)), poisoned(_mm_set1_epi16(7), _mm_set1_epi16(0)))); } #endif // Volatile bitfield store is implemented as load-mask-store // Test that we don't warn on the store of (uninitialized) padding. struct VolatileBitfieldStruct { volatile unsigned x : 1; unsigned y : 1; }; TEST(MemorySanitizer, VolatileBitfield) { VolatileBitfieldStruct *S = new VolatileBitfieldStruct; S->x = 1; EXPECT_NOT_POISONED((unsigned)S->x); EXPECT_POISONED((unsigned)S->y); } TEST(MemorySanitizer, UnalignedLoad) { - char x[32]; + char x[32] __attribute__((aligned(8))); U4 origin = __LINE__; for (unsigned i = 0; i < sizeof(x) / 4; ++i) __msan_set_origin(x + 4 * i, 4, origin + i); memset(x + 8, 0, 16); EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 6), origin + 1); EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 7), origin + 1); EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 8)); EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 9)); EXPECT_NOT_POISONED(__sanitizer_unaligned_load16(x + 22)); EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 23), origin + 6); EXPECT_POISONED_O(__sanitizer_unaligned_load16(x + 24), origin + 6); EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 4), origin + 1); EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 7), origin + 1); EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 8)); EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 9)); EXPECT_NOT_POISONED(__sanitizer_unaligned_load32(x + 20)); EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 21), origin + 6); EXPECT_POISONED_O(__sanitizer_unaligned_load32(x + 24), origin + 6); EXPECT_POISONED_O(__sanitizer_unaligned_load64(x), origin); EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 1), origin); EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 7), origin + 1); EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 8)); EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 9)); EXPECT_NOT_POISONED(__sanitizer_unaligned_load64(x + 16)); EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 17), origin + 6); EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 21), origin + 6); EXPECT_POISONED_O(__sanitizer_unaligned_load64(x + 24), origin + 6); } TEST(MemorySanitizer, UnalignedStore16) { - char x[5]; + char x[5] __attribute__((aligned(4))); U2 y2 = 0; U4 origin = __LINE__; __msan_poison(&y2, 1); __msan_set_origin(&y2, 1, origin); __sanitizer_unaligned_store16(x + 1, y2); EXPECT_POISONED_O(x[0], origin); EXPECT_POISONED_O(x[1], origin); EXPECT_NOT_POISONED(x[2]); EXPECT_POISONED_O(x[3], origin); - EXPECT_POISONED_O(x[4], origin); } TEST(MemorySanitizer, UnalignedStore32) { - char x[8]; + char x[8] __attribute__((aligned(4))); U4 y4 = 0; U4 origin = __LINE__; __msan_poison(&y4, 2); __msan_set_origin(&y4, 2, origin); __sanitizer_unaligned_store32(x + 3, y4); EXPECT_POISONED_O(x[0], origin); EXPECT_POISONED_O(x[1], origin); EXPECT_POISONED_O(x[2], origin); EXPECT_POISONED_O(x[3], origin); EXPECT_POISONED_O(x[4], origin); EXPECT_NOT_POISONED(x[5]); EXPECT_NOT_POISONED(x[6]); EXPECT_POISONED_O(x[7], origin); } TEST(MemorySanitizer, UnalignedStore64) { - char x[16]; + char x[16] __attribute__((aligned(8))); U8 y8 = 0; U4 origin = __LINE__; __msan_poison(&y8, 3); __msan_poison(((char *)&y8) + sizeof(y8) - 2, 1); __msan_set_origin(&y8, 8, origin); __sanitizer_unaligned_store64(x + 3, y8); EXPECT_POISONED_O(x[0], origin); EXPECT_POISONED_O(x[1], origin); EXPECT_POISONED_O(x[2], origin); EXPECT_POISONED_O(x[3], origin); EXPECT_POISONED_O(x[4], origin); EXPECT_POISONED_O(x[5], origin); EXPECT_NOT_POISONED(x[6]); EXPECT_NOT_POISONED(x[7]); EXPECT_NOT_POISONED(x[8]); EXPECT_POISONED_O(x[9], origin); EXPECT_NOT_POISONED(x[10]); EXPECT_POISONED_O(x[11], origin); } TEST(MemorySanitizer, UnalignedStore16_precise) { - char x[8]; + char x[8] __attribute__((aligned(4))); U2 y = 0; U4 originx1 = __LINE__; U4 originx2 = __LINE__; U4 originy = __LINE__; __msan_poison(x, sizeof(x)); __msan_set_origin(x, 4, originx1); __msan_set_origin(x + 4, 4, originx2); __msan_poison(((char *)&y) + 1, 1); __msan_set_origin(&y, sizeof(y), originy); __sanitizer_unaligned_store16(x + 3, y); EXPECT_POISONED_O(x[0], originx1); EXPECT_POISONED_O(x[1], originx1); EXPECT_POISONED_O(x[2], originx1); EXPECT_NOT_POISONED(x[3]); EXPECT_POISONED_O(x[4], originy); EXPECT_POISONED_O(x[5], originy); EXPECT_POISONED_O(x[6], originy); EXPECT_POISONED_O(x[7], originy); } TEST(MemorySanitizer, UnalignedStore16_precise2) { - char x[8]; + char x[8] __attribute__((aligned(4))); U2 y = 0; U4 originx1 = __LINE__; U4 originx2 = __LINE__; U4 originy = __LINE__; __msan_poison(x, sizeof(x)); __msan_set_origin(x, 4, originx1); __msan_set_origin(x + 4, 4, originx2); __msan_poison(((char *)&y), 1); __msan_set_origin(&y, sizeof(y), originy); __sanitizer_unaligned_store16(x + 3, y); EXPECT_POISONED_O(x[0], originy); EXPECT_POISONED_O(x[1], originy); EXPECT_POISONED_O(x[2], originy); EXPECT_POISONED_O(x[3], originy); EXPECT_NOT_POISONED(x[4]); EXPECT_POISONED_O(x[5], originx2); EXPECT_POISONED_O(x[6], originx2); EXPECT_POISONED_O(x[7], originx2); } TEST(MemorySanitizer, UnalignedStore64_precise) { - char x[12]; + char x[12] __attribute__((aligned(8))); U8 y = 0; U4 originx1 = __LINE__; U4 originx2 = __LINE__; U4 originx3 = __LINE__; U4 originy = __LINE__; __msan_poison(x, sizeof(x)); __msan_set_origin(x, 4, originx1); __msan_set_origin(x + 4, 4, originx2); __msan_set_origin(x + 8, 4, originx3); __msan_poison(((char *)&y) + 1, 1); __msan_poison(((char *)&y) + 7, 1); __msan_set_origin(&y, sizeof(y), originy); __sanitizer_unaligned_store64(x + 2, y); EXPECT_POISONED_O(x[0], originy); EXPECT_POISONED_O(x[1], originy); EXPECT_NOT_POISONED(x[2]); EXPECT_POISONED_O(x[3], originy); EXPECT_NOT_POISONED(x[4]); EXPECT_NOT_POISONED(x[5]); EXPECT_NOT_POISONED(x[6]); EXPECT_NOT_POISONED(x[7]); EXPECT_NOT_POISONED(x[8]); EXPECT_POISONED_O(x[9], originy); EXPECT_POISONED_O(x[10], originy); EXPECT_POISONED_O(x[11], originy); } TEST(MemorySanitizer, UnalignedStore64_precise2) { - char x[12]; + char x[12] __attribute__((aligned(8))); U8 y = 0; U4 originx1 = __LINE__; U4 originx2 = __LINE__; U4 originx3 = __LINE__; U4 originy = __LINE__; __msan_poison(x, sizeof(x)); __msan_set_origin(x, 4, originx1); __msan_set_origin(x + 4, 4, originx2); __msan_set_origin(x + 8, 4, originx3); __msan_poison(((char *)&y) + 3, 3); __msan_set_origin(&y, sizeof(y), originy); __sanitizer_unaligned_store64(x + 2, y); EXPECT_POISONED_O(x[0], originx1); EXPECT_POISONED_O(x[1], originx1); EXPECT_NOT_POISONED(x[2]); EXPECT_NOT_POISONED(x[3]); EXPECT_NOT_POISONED(x[4]); EXPECT_POISONED_O(x[5], originy); EXPECT_POISONED_O(x[6], originy); EXPECT_POISONED_O(x[7], originy); EXPECT_NOT_POISONED(x[8]); EXPECT_NOT_POISONED(x[9]); EXPECT_POISONED_O(x[10], originx3); EXPECT_POISONED_O(x[11], originx3); } #if (defined(__x86_64__) && defined(__clang__)) namespace { typedef U1 V16x8 __attribute__((__vector_size__(16))); typedef U2 V8x16 __attribute__((__vector_size__(16))); typedef U4 V4x32 __attribute__((__vector_size__(16))); typedef U8 V2x64 __attribute__((__vector_size__(16))); typedef U4 V8x32 __attribute__((__vector_size__(32))); typedef U8 V4x64 __attribute__((__vector_size__(32))); typedef U4 V2x32 __attribute__((__vector_size__(8))); typedef U2 V4x16 __attribute__((__vector_size__(8))); typedef U1 V8x8 __attribute__((__vector_size__(8))); V8x16 shift_sse2_left_scalar(V8x16 x, U4 y) { return _mm_slli_epi16(x, y); } V8x16 shift_sse2_left(V8x16 x, V8x16 y) { return _mm_sll_epi16(x, y); } TEST(VectorShiftTest, sse2_left_scalar) { V8x16 v = {Poisoned(0, 3), Poisoned(0, 7), 2, 3, 4, 5, 6, 7}; V8x16 u = shift_sse2_left_scalar(v, 2); EXPECT_POISONED(u[0]); EXPECT_POISONED(u[1]); EXPECT_NOT_POISONED(u[0] | (3U << 2)); EXPECT_NOT_POISONED(u[1] | (7U << 2)); u[0] = u[1] = 0; EXPECT_NOT_POISONED(u); } TEST(VectorShiftTest, sse2_left_scalar_by_uninit) { V8x16 v = {0, 1, 2, 3, 4, 5, 6, 7}; V8x16 u = shift_sse2_left_scalar(v, Poisoned()); EXPECT_POISONED(u[0]); EXPECT_POISONED(u[1]); EXPECT_POISONED(u[2]); EXPECT_POISONED(u[3]); EXPECT_POISONED(u[4]); EXPECT_POISONED(u[5]); EXPECT_POISONED(u[6]); EXPECT_POISONED(u[7]); } TEST(VectorShiftTest, sse2_left) { V8x16 v = {Poisoned(0, 3), Poisoned(0, 7), 2, 3, 4, 5, 6, 7}; // Top 64 bits of shift count don't affect the result. V2x64 s = {2, Poisoned()}; V8x16 u = shift_sse2_left(v, s); EXPECT_POISONED(u[0]); EXPECT_POISONED(u[1]); EXPECT_NOT_POISONED(u[0] | (3U << 2)); EXPECT_NOT_POISONED(u[1] | (7U << 2)); u[0] = u[1] = 0; EXPECT_NOT_POISONED(u); } TEST(VectorShiftTest, sse2_left_by_uninit) { V8x16 v = {Poisoned(0, 3), Poisoned(0, 7), 2, 3, 4, 5, 6, 7}; V2x64 s = {Poisoned(), Poisoned()}; V8x16 u = shift_sse2_left(v, s); EXPECT_POISONED(u[0]); EXPECT_POISONED(u[1]); EXPECT_POISONED(u[2]); EXPECT_POISONED(u[3]); EXPECT_POISONED(u[4]); EXPECT_POISONED(u[5]); EXPECT_POISONED(u[6]); EXPECT_POISONED(u[7]); } #ifdef __AVX2__ V4x32 shift_avx2_left(V4x32 x, V4x32 y) { return _mm_sllv_epi32(x, y); } // This is variable vector shift that's only available starting with AVX2. // V4x32 shift_avx2_left(V4x32 x, V4x32 y) { TEST(VectorShiftTest, avx2_left) { V4x32 v = {Poisoned(0, 3), Poisoned(0, 7), 2, 3}; V4x32 s = {2, Poisoned(), 3, Poisoned()}; V4x32 u = shift_avx2_left(v, s); EXPECT_POISONED(u[0]); EXPECT_NOT_POISONED(u[0] | (~7U)); EXPECT_POISONED(u[1]); EXPECT_POISONED(u[1] | (~31U)); EXPECT_NOT_POISONED(u[2]); EXPECT_POISONED(u[3]); EXPECT_POISONED(u[3] | (~31U)); } #endif // __AVX2__ } // namespace TEST(VectorPackTest, sse2_packssdw_128) { const unsigned S2_max = (1 << 15) - 1; V4x32 a = {Poisoned(0, 0xFF0000), Poisoned(0, 0xFFFF0000), S2_max + 100, 4}; V4x32 b = {Poisoned(0, 0xFF), S2_max + 10000, Poisoned(0, 0xFF00), S2_max}; V8x16 c = _mm_packs_epi32(a, b); EXPECT_POISONED(c[0]); EXPECT_POISONED(c[1]); EXPECT_NOT_POISONED(c[2]); EXPECT_NOT_POISONED(c[3]); EXPECT_POISONED(c[4]); EXPECT_NOT_POISONED(c[5]); EXPECT_POISONED(c[6]); EXPECT_NOT_POISONED(c[7]); EXPECT_EQ(c[2], S2_max); EXPECT_EQ(c[3], 4); EXPECT_EQ(c[5], S2_max); EXPECT_EQ(c[7], S2_max); } TEST(VectorPackTest, mmx_packuswb) { const unsigned U1_max = (1 << 8) - 1; V4x16 a = {Poisoned(0, 0xFF00), Poisoned(0, 0xF000U), U1_max + 100, 4}; V4x16 b = {Poisoned(0, 0xFF), U1_max - 1, Poisoned(0, 0xF), U1_max}; V8x8 c = _mm_packs_pu16(a, b); EXPECT_POISONED(c[0]); EXPECT_POISONED(c[1]); EXPECT_NOT_POISONED(c[2]); EXPECT_NOT_POISONED(c[3]); EXPECT_POISONED(c[4]); EXPECT_NOT_POISONED(c[5]); EXPECT_POISONED(c[6]); EXPECT_NOT_POISONED(c[7]); EXPECT_EQ(c[2], U1_max); EXPECT_EQ(c[3], 4); EXPECT_EQ(c[5], U1_max - 1); EXPECT_EQ(c[7], U1_max); } TEST(VectorSadTest, sse2_psad_bw) { V16x8 a = {Poisoned(), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; V16x8 b = {100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115}; V2x64 c = _mm_sad_epu8(a, b); EXPECT_POISONED(c[0]); EXPECT_NOT_POISONED(c[1]); EXPECT_EQ(800U, c[1]); } TEST(VectorMaddTest, mmx_pmadd_wd) { V4x16 a = {Poisoned(), 1, 2, 3}; V4x16 b = {100, 101, 102, 103}; V2x32 c = _mm_madd_pi16(a, b); EXPECT_POISONED(c[0]); EXPECT_NOT_POISONED(c[1]); EXPECT_EQ((unsigned)(2 * 102 + 3 * 103), c[1]); } #endif // defined(__clang__) TEST(MemorySanitizerOrigins, SetGet) { EXPECT_EQ(TrackingOrigins(), __msan_get_track_origins()); if (!TrackingOrigins()) return; int x; __msan_set_origin(&x, sizeof(x), 1234); EXPECT_EQ(1234U, __msan_get_origin(&x)); __msan_set_origin(&x, sizeof(x), 5678); EXPECT_EQ(5678U, __msan_get_origin(&x)); __msan_set_origin(&x, sizeof(x), 0); EXPECT_EQ(0U, __msan_get_origin(&x)); } namespace { struct S { U4 dummy; U2 a; U2 b; }; TEST(MemorySanitizerOrigins, InitializedStoreDoesNotChangeOrigin) { if (!TrackingOrigins()) return; S s; U4 origin = rand(); // NOLINT s.a = *GetPoisonedO(0, origin); EXPECT_EQ(origin, __msan_get_origin(&s.a)); EXPECT_EQ(origin, __msan_get_origin(&s.b)); s.b = 42; EXPECT_EQ(origin, __msan_get_origin(&s.a)); EXPECT_EQ(origin, __msan_get_origin(&s.b)); } } // namespace template INLINE void BinaryOpOriginTest(BinaryOp op) { U4 ox = rand(); //NOLINT U4 oy = rand(); //NOLINT T *x = GetPoisonedO(0, ox, 0); T *y = GetPoisonedO(1, oy, 0); T *z = GetPoisonedO(2, 0, 0); *z = op(*x, *y); U4 origin = __msan_get_origin(z); EXPECT_POISONED_O(*z, origin); EXPECT_EQ(true, origin == ox || origin == oy); // y is poisoned, x is not. *x = 10101; *y = *GetPoisonedO(1, oy); break_optimization(x); __msan_set_origin(z, sizeof(*z), 0); *z = op(*x, *y); EXPECT_POISONED_O(*z, oy); EXPECT_EQ(__msan_get_origin(z), oy); // x is poisoned, y is not. *x = *GetPoisonedO(0, ox); *y = 10101010; break_optimization(y); __msan_set_origin(z, sizeof(*z), 0); *z = op(*x, *y); EXPECT_POISONED_O(*z, ox); EXPECT_EQ(__msan_get_origin(z), ox); } template INLINE T XOR(const T &a, const T&b) { return a ^ b; } template INLINE T ADD(const T &a, const T&b) { return a + b; } template INLINE T SUB(const T &a, const T&b) { return a - b; } template INLINE T MUL(const T &a, const T&b) { return a * b; } template INLINE T AND(const T &a, const T&b) { return a & b; } template INLINE T OR (const T &a, const T&b) { return a | b; } TEST(MemorySanitizerOrigins, BinaryOp) { if (!TrackingOrigins()) return; BinaryOpOriginTest(XOR); BinaryOpOriginTest(ADD); BinaryOpOriginTest(SUB); BinaryOpOriginTest(MUL); BinaryOpOriginTest(OR); BinaryOpOriginTest(AND); BinaryOpOriginTest(ADD); BinaryOpOriginTest(ADD); BinaryOpOriginTest(ADD); BinaryOpOriginTest(ADD); } TEST(MemorySanitizerOrigins, Unary) { if (!TrackingOrigins()) return; EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O((void*)*GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O((U8)*GetPoisonedO(0, __LINE__), __LINE__); } TEST(MemorySanitizerOrigins, EQ) { if (!TrackingOrigins()) return; EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__) <= 11, __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__) == 11, __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__) == 1.1, __LINE__); } TEST(MemorySanitizerOrigins, DIV) { if (!TrackingOrigins()) return; EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__) / 100, __LINE__); unsigned o = __LINE__; EXPECT_UMR_O(volatile unsigned y = 100 / *GetPoisonedO(0, o, 1), o); } TEST(MemorySanitizerOrigins, SHIFT) { if (!TrackingOrigins()) return; EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__) >> 10, __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__) >> 10, __LINE__); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__) << 10, __LINE__); EXPECT_POISONED_O(10U << *GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(-10 >> *GetPoisonedO(0, __LINE__), __LINE__); EXPECT_POISONED_O(-10 << *GetPoisonedO(0, __LINE__), __LINE__); } template void MemCpyTest() { int ox = __LINE__; T *x = new T[N]; T *y = new T[N]; T *z = new T[N]; T *q = new T[N]; __msan_poison(x, N * sizeof(T)); __msan_set_origin(x, N * sizeof(T), ox); __msan_set_origin(y, N * sizeof(T), 777777); __msan_set_origin(z, N * sizeof(T), 888888); EXPECT_NOT_POISONED(x); memcpy(y, x, N * sizeof(T)); EXPECT_POISONED_O(y[0], ox); EXPECT_POISONED_O(y[N/2], ox); EXPECT_POISONED_O(y[N-1], ox); EXPECT_NOT_POISONED(x); void *res = mempcpy(q, x, N * sizeof(T)); ASSERT_EQ(q + N, res); EXPECT_POISONED_O(q[0], ox); EXPECT_POISONED_O(q[N/2], ox); EXPECT_POISONED_O(q[N-1], ox); EXPECT_NOT_POISONED(x); memmove(z, x, N * sizeof(T)); EXPECT_POISONED_O(z[0], ox); EXPECT_POISONED_O(z[N/2], ox); EXPECT_POISONED_O(z[N-1], ox); } TEST(MemorySanitizerOrigins, LargeMemCpy) { if (!TrackingOrigins()) return; MemCpyTest(); MemCpyTest(); } TEST(MemorySanitizerOrigins, SmallMemCpy) { if (!TrackingOrigins()) return; MemCpyTest(); MemCpyTest(); MemCpyTest(); } TEST(MemorySanitizerOrigins, Select) { if (!TrackingOrigins()) return; EXPECT_NOT_POISONED(g_one ? 1 : *GetPoisonedO(0, __LINE__)); EXPECT_POISONED_O(*GetPoisonedO(0, __LINE__), __LINE__); S4 x; break_optimization(&x); x = g_1 ? *GetPoisonedO(0, __LINE__) : 0; EXPECT_POISONED_O(g_1 ? *GetPoisonedO(0, __LINE__) : 1, __LINE__); EXPECT_POISONED_O(g_0 ? 1 : *GetPoisonedO(0, __LINE__), __LINE__); } NOINLINE int RetvalOriginTest(U4 origin) { int *a = new int; break_optimization(a); __msan_set_origin(a, sizeof(*a), origin); int res = *a; delete a; return res; } TEST(MemorySanitizerOrigins, Retval) { if (!TrackingOrigins()) return; EXPECT_POISONED_O(RetvalOriginTest(__LINE__), __LINE__); } NOINLINE void ParamOriginTest(int param, U4 origin) { EXPECT_POISONED_O(param, origin); } TEST(MemorySanitizerOrigins, Param) { if (!TrackingOrigins()) return; int *a = new int; U4 origin = __LINE__; break_optimization(a); __msan_set_origin(a, sizeof(*a), origin); ParamOriginTest(*a, origin); delete a; } TEST(MemorySanitizerOrigins, Invoke) { if (!TrackingOrigins()) return; StructWithDtor s; // Will cause the calls to become invokes. EXPECT_POISONED_O(RetvalOriginTest(__LINE__), __LINE__); } TEST(MemorySanitizerOrigins, strlen) { S8 alignment; break_optimization(&alignment); char x[4] = {'a', 'b', 0, 0}; __msan_poison(&x[2], 1); U4 origin = __LINE__; __msan_set_origin(x, sizeof(x), origin); EXPECT_UMR_O(volatile unsigned y = strlen(x), origin); } TEST(MemorySanitizerOrigins, wcslen) { wchar_t w[3] = {'a', 'b', 0}; U4 origin = __LINE__; __msan_set_origin(w, sizeof(w), origin); __msan_poison(&w[2], sizeof(wchar_t)); EXPECT_UMR_O(volatile unsigned y = wcslen(w), origin); } #if MSAN_HAS_M128 TEST(MemorySanitizerOrigins, StoreIntrinsic) { __m128 x, y; U4 origin = __LINE__; __msan_set_origin(&x, sizeof(x), origin); __msan_poison(&x, sizeof(x)); __builtin_ia32_storeups((float*)&y, x); EXPECT_POISONED_O(y, origin); } #endif NOINLINE void RecursiveMalloc(int depth) { static int count; count++; if ((count % (1024 * 1024)) == 0) printf("RecursiveMalloc: %d\n", count); int *x1 = new int; int *x2 = new int; break_optimization(x1); break_optimization(x2); if (depth > 0) { RecursiveMalloc(depth-1); RecursiveMalloc(depth-1); } delete x1; delete x2; } TEST(MemorySanitizer, Select) { int x; int volatile* p = &x; int z = *p ? 1 : 0; EXPECT_POISONED(z); } TEST(MemorySanitizer, SelectPartial) { // Precise instrumentation of select. // Some bits of the result do not depend on select condition, and must stay // initialized even if select condition is not. These are the bits that are // equal and initialized in both left and right select arguments. U4 x = 0xFFFFABCDU; U4 x_s = 0xFFFF0000U; __msan_partial_poison(&x, &x_s, sizeof(x)); U4 y = 0xAB00U; U1 cond = true; __msan_poison(&cond, sizeof(cond)); U4 z = cond ? x : y; __msan_print_shadow(&z, sizeof(z)); EXPECT_POISONED(z & 0xFFU); EXPECT_NOT_POISONED(z & 0xFF00U); EXPECT_POISONED(z & 0xFF0000U); EXPECT_POISONED(z & 0xFF000000U); EXPECT_EQ(0xAB00U, z & 0xFF00U); } TEST(MemorySanitizerStress, DISABLED_MallocStackTrace) { RecursiveMalloc(22); } TEST(MemorySanitizerAllocator, get_estimated_allocated_size) { size_t sizes[] = {0, 20, 5000, 1<<20}; for (size_t i = 0; i < sizeof(sizes) / sizeof(*sizes); ++i) { size_t alloc_size = __sanitizer_get_estimated_allocated_size(sizes[i]); EXPECT_EQ(alloc_size, sizes[i]); } } TEST(MemorySanitizerAllocator, get_allocated_size_and_ownership) { char *array = reinterpret_cast(malloc(100)); int *int_ptr = new int; EXPECT_TRUE(__sanitizer_get_ownership(array)); EXPECT_EQ(100U, __sanitizer_get_allocated_size(array)); EXPECT_TRUE(__sanitizer_get_ownership(int_ptr)); EXPECT_EQ(sizeof(*int_ptr), __sanitizer_get_allocated_size(int_ptr)); void *wild_addr = reinterpret_cast(0x1); EXPECT_FALSE(__sanitizer_get_ownership(wild_addr)); EXPECT_EQ(0U, __sanitizer_get_allocated_size(wild_addr)); EXPECT_FALSE(__sanitizer_get_ownership(array + 50)); EXPECT_EQ(0U, __sanitizer_get_allocated_size(array + 50)); // NULL is a valid argument for GetAllocatedSize but is not owned. EXPECT_FALSE(__sanitizer_get_ownership(NULL)); EXPECT_EQ(0U, __sanitizer_get_allocated_size(NULL)); free(array); EXPECT_FALSE(__sanitizer_get_ownership(array)); EXPECT_EQ(0U, __sanitizer_get_allocated_size(array)); delete int_ptr; } TEST(MemorySanitizer, MlockTest) { EXPECT_EQ(0, mlockall(MCL_CURRENT)); EXPECT_EQ(0, mlock((void*)0x12345, 0x5678)); EXPECT_EQ(0, munlockall()); EXPECT_EQ(0, munlock((void*)0x987, 0x654)); } // Test that LargeAllocator unpoisons memory before releasing it to the OS. TEST(MemorySanitizer, LargeAllocatorUnpoisonsOnFree) { void *p = malloc(1024 * 1024); free(p); typedef void *(*mmap_fn)(void *, size_t, int, int, int, off_t); mmap_fn real_mmap = (mmap_fn)dlsym(RTLD_NEXT, "mmap"); // Allocate the page that was released to the OS in free() with the real mmap, // bypassing the interceptor. char *q = (char *)real_mmap(p, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_NE((char *)0, q); ASSERT_TRUE(q <= p); ASSERT_TRUE(q + 4096 > p); EXPECT_NOT_POISONED(q[0]); EXPECT_NOT_POISONED(q[10]); EXPECT_NOT_POISONED(q[100]); munmap(q, 4096); } #if SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE TEST(MemorySanitizer, MallocUsableSizeTest) { const size_t kArraySize = 100; char *array = Ident((char*)malloc(kArraySize)); int *int_ptr = Ident(new int); EXPECT_EQ(0U, malloc_usable_size(NULL)); EXPECT_EQ(kArraySize, malloc_usable_size(array)); EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr)); free(array); delete int_ptr; } #endif // SANITIZER_TEST_HAS_MALLOC_USABLE_SIZE Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.cc (revision 279194) @@ -1,308 +1,350 @@ //===-- sanitizer_common.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 shared between AddressSanitizer and ThreadSanitizer // run-time libraries. //===----------------------------------------------------------------------===// #include "sanitizer_common.h" #include "sanitizer_allocator_internal.h" #include "sanitizer_flags.h" #include "sanitizer_libc.h" #include "sanitizer_placement_new.h" namespace __sanitizer { const char *SanitizerToolName = "SanitizerTool"; atomic_uint32_t current_verbosity; uptr GetPageSizeCached() { static uptr PageSize; if (!PageSize) PageSize = GetPageSize(); return PageSize; } StaticSpinMutex report_file_mu; ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; void RawWrite(const char *buffer) { report_file.Write(buffer, internal_strlen(buffer)); } void ReportFile::ReopenIfNecessary() { mu->CheckLocked(); if (fd == kStdoutFd || fd == kStderrFd) return; uptr pid = internal_getpid(); // If in tracer, use the parent's file. if (pid == stoptheworld_tracer_pid) pid = stoptheworld_tracer_ppid; if (fd != kInvalidFd) { // If the report file is already opened by the current process, // do nothing. Otherwise the report file was opened by the parent // process, close it now. if (fd_pid == pid) return; else internal_close(fd); } internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); uptr openrv = OpenFile(full_path, true); if (internal_iserror(openrv)) { const char *ErrorMsgPrefix = "ERROR: Can't open file: "; internal_write(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); internal_write(kStderrFd, full_path, internal_strlen(full_path)); Die(); } fd = openrv; fd_pid = pid; } void ReportFile::SetReportPath(const char *path) { if (!path) return; uptr len = internal_strlen(path); if (len > sizeof(path_prefix) - 100) { Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", path[0], path[1], path[2], path[3], path[4], path[5], path[6], path[7]); Die(); } SpinMutexLock l(mu); if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) internal_close(fd); fd = kInvalidFd; if (internal_strcmp(path, "stdout") == 0) { fd = kStdoutFd; } else if (internal_strcmp(path, "stderr") == 0) { fd = kStderrFd; } else { internal_snprintf(path_prefix, kMaxPathLength, "%s", path); } } // PID of the tracer task in StopTheWorld. It shares the address space with the // main process, but has a different PID and thus requires special handling. uptr stoptheworld_tracer_pid = 0; // Cached pid of parent process - if the parent process dies, we want to keep // writing to the same log file. uptr stoptheworld_tracer_ppid = 0; static DieCallbackType InternalDieCallback, UserDieCallback; void SetDieCallback(DieCallbackType callback) { InternalDieCallback = callback; } void SetUserDieCallback(DieCallbackType callback) { UserDieCallback = callback; } DieCallbackType GetDieCallback() { return InternalDieCallback; } void NORETURN Die() { if (UserDieCallback) UserDieCallback(); if (InternalDieCallback) InternalDieCallback(); internal__exit(1); } static CheckFailedCallbackType CheckFailedCallback; void SetCheckFailedCallback(CheckFailedCallbackType callback) { CheckFailedCallback = callback; } void NORETURN CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2) { if (CheckFailedCallback) { CheckFailedCallback(file, line, cond, v1, v2); } Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond, v1, v2); Die(); } uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, uptr max_len, int *errno_p) { uptr PageSize = GetPageSizeCached(); uptr kMinFileLen = PageSize; uptr read_len = 0; *buff = 0; *buff_size = 0; // The files we usually open are not seekable, so try different buffer sizes. for (uptr size = kMinFileLen; size <= max_len; size *= 2) { uptr openrv = OpenFile(file_name, /*write*/ false); if (internal_iserror(openrv, errno_p)) return 0; fd_t fd = openrv; UnmapOrDie(*buff, *buff_size); *buff = (char*)MmapOrDie(size, __func__); *buff_size = size; // Read up to one page at a time. read_len = 0; bool reached_eof = false; while (read_len + PageSize <= size) { uptr just_read = internal_read(fd, *buff + read_len, PageSize); if (internal_iserror(just_read, errno_p)) { UnmapOrDie(*buff, *buff_size); return 0; } if (just_read == 0) { reached_eof = true; break; } read_len += just_read; } internal_close(fd); if (reached_eof) // We've read the whole file. break; } return read_len; } typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); template static inline bool CompareLess(const T &a, const T &b) { return a < b; } void SortArray(uptr *array, uptr size) { InternalSort(&array, size, CompareLess); } // We want to map a chunk of address space aligned to 'alignment'. // We do it by maping a bit more and then unmaping redundant pieces. // We probably can do it with fewer syscalls in some OS-dependent way. void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { // uptr PageSize = GetPageSizeCached(); CHECK(IsPowerOfTwo(size)); CHECK(IsPowerOfTwo(alignment)); uptr map_size = size + alignment; uptr map_res = (uptr)MmapOrDie(map_size, mem_type); uptr map_end = map_res + map_size; uptr res = map_res; if (res & (alignment - 1)) // Not aligned. res = (map_res + alignment) & ~(alignment - 1); uptr end = res + size; if (res != map_res) UnmapOrDie((void*)map_res, res - map_res); if (end != map_end) UnmapOrDie((void*)end, map_end - end); return (void*)res; } const char *StripPathPrefix(const char *filepath, const char *strip_path_prefix) { if (filepath == 0) return 0; if (strip_path_prefix == 0) return filepath; const char *pos = internal_strstr(filepath, strip_path_prefix); if (pos == 0) return filepath; pos += internal_strlen(strip_path_prefix); if (pos[0] == '.' && pos[1] == '/') pos += 2; return pos; } const char *StripModuleName(const char *module) { if (module == 0) return 0; if (const char *slash_pos = internal_strrchr(module, '/')) return slash_pos + 1; return module; } void ReportErrorSummary(const char *error_message) { if (!common_flags()->print_summary) return; InternalScopedString buff(kMaxSummaryLength); buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message); __sanitizer_report_error_summary(buff.data()); } void ReportErrorSummary(const char *error_type, const char *file, int line, const char *function) { if (!common_flags()->print_summary) return; InternalScopedString buff(kMaxSummaryLength); buff.append("%s %s:%d %s", error_type, file ? StripPathPrefix(file, common_flags()->strip_path_prefix) : "??", line, function ? function : "??"); ReportErrorSummary(buff.data()); } LoadedModule::LoadedModule(const char *module_name, uptr base_address) { full_name_ = internal_strdup(module_name); base_address_ = base_address; ranges_.clear(); } void LoadedModule::clear() { InternalFree(full_name_); while (!ranges_.empty()) { AddressRange *r = ranges_.front(); ranges_.pop_front(); InternalFree(r); } } void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) { void *mem = InternalAlloc(sizeof(AddressRange)); AddressRange *r = new(mem) AddressRange(beg, end, executable); ranges_.push_back(r); } bool LoadedModule::containsAddress(uptr address) const { for (Iterator iter = ranges(); iter.hasNext();) { const AddressRange *r = iter.next(); if (r->beg <= address && address < r->end) return true; } return false; } static atomic_uintptr_t g_total_mmaped; void IncreaseTotalMmap(uptr size) { if (!common_flags()->mmap_limit_mb) return; uptr total_mmaped = atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size; // Since for now mmap_limit_mb is not a user-facing flag, just kill // a program. Use RAW_CHECK to avoid extra mmaps in reporting. RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb); } void DecreaseTotalMmap(uptr size) { if (!common_flags()->mmap_limit_mb) return; atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed); } +bool TemplateMatch(const char *templ, const char *str) { + if (str == 0 || str[0] == 0) + return false; + bool start = false; + if (templ && templ[0] == '^') { + start = true; + templ++; + } + bool asterisk = false; + while (templ && templ[0]) { + if (templ[0] == '*') { + templ++; + start = false; + asterisk = true; + continue; + } + if (templ[0] == '$') + return str[0] == 0 || asterisk; + if (str[0] == 0) + return false; + char *tpos = (char*)internal_strchr(templ, '*'); + char *tpos1 = (char*)internal_strchr(templ, '$'); + if (tpos == 0 || (tpos1 && tpos1 < tpos)) + tpos = tpos1; + if (tpos != 0) + tpos[0] = 0; + const char *str0 = str; + const char *spos = internal_strstr(str, templ); + str = spos + internal_strlen(templ); + templ = tpos; + if (tpos) + tpos[0] = tpos == tpos1 ? '$' : '*'; + if (spos == 0) + return false; + if (start && spos != str0) + return false; + start = false; + asterisk = false; + } + return true; +} + } // namespace __sanitizer using namespace __sanitizer; // NOLINT extern "C" { void __sanitizer_set_report_path(const char *path) { report_file.SetReportPath(path); } void __sanitizer_report_error_summary(const char *error_summary) { Printf("%s\n", error_summary); } SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_set_death_callback(void (*callback)(void)) { SetUserDieCallback(callback); } } // extern "C" Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h (revision 279194) @@ -1,620 +1,622 @@ //===-- sanitizer_common.h --------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // -// This file is shared between AddressSanitizer and ThreadSanitizer -// run-time libraries. +// This file is shared between run-time libraries of sanitizers. +// // It declares common functions and classes that are used in both runtimes. // Implementation of some functions are provided in sanitizer_common, while // others must be defined by run-time library itself. //===----------------------------------------------------------------------===// #ifndef SANITIZER_COMMON_H #define SANITIZER_COMMON_H #include "sanitizer_flags.h" +#include "sanitizer_interface_internal.h" #include "sanitizer_internal_defs.h" #include "sanitizer_libc.h" #include "sanitizer_list.h" #include "sanitizer_mutex.h" namespace __sanitizer { struct StackTrace; // Constants. const uptr kWordSize = SANITIZER_WORDSIZE / 8; const uptr kWordSizeInBits = 8 * kWordSize; #if defined(__powerpc__) || defined(__powerpc64__) const uptr kCacheLineSize = 128; #else const uptr kCacheLineSize = 64; #endif const uptr kMaxPathLength = 4096; const uptr kMaxThreadStackSize = 1 << 30; // 1Gb extern const char *SanitizerToolName; // Can be changed by the tool. extern atomic_uint32_t current_verbosity; INLINE void SetVerbosity(int verbosity) { atomic_store(¤t_verbosity, verbosity, memory_order_relaxed); } INLINE int Verbosity() { return atomic_load(¤t_verbosity, memory_order_relaxed); } uptr GetPageSize(); uptr GetPageSizeCached(); uptr GetMmapGranularity(); uptr GetMaxVirtualAddress(); // Threads uptr GetTid(); uptr GetThreadSelf(); void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, uptr *stack_bottom); void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, uptr *tls_addr, uptr *tls_size); // Memory management void *MmapOrDie(uptr size, const char *mem_type); void UnmapOrDie(void *addr, uptr size); void *MmapFixedNoReserve(uptr fixed_addr, uptr size); void *MmapNoReserveOrDie(uptr size, const char *mem_type); void *MmapFixedOrDie(uptr fixed_addr, uptr size); void *Mprotect(uptr fixed_addr, uptr size); // Map aligned chunk of address space; size and alignment are powers of two. void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type); // Used to check if we can map shadow memory to a fixed location. bool MemoryRangeIsAvailable(uptr range_start, uptr range_end); void FlushUnneededShadowMemory(uptr addr, uptr size); void IncreaseTotalMmap(uptr size); void DecreaseTotalMmap(uptr size); uptr GetRSS(); void NoHugePagesInRegion(uptr addr, uptr length); void DontDumpShadowMemory(uptr addr, uptr length); // InternalScopedBuffer can be used instead of large stack arrays to // keep frame size low. // FIXME: use InternalAlloc instead of MmapOrDie once // InternalAlloc is made libc-free. template class InternalScopedBuffer { public: explicit InternalScopedBuffer(uptr cnt) { cnt_ = cnt; ptr_ = (T*)MmapOrDie(cnt * sizeof(T), "InternalScopedBuffer"); } ~InternalScopedBuffer() { UnmapOrDie(ptr_, cnt_ * sizeof(T)); } T &operator[](uptr i) { return ptr_[i]; } T *data() { return ptr_; } uptr size() { return cnt_ * sizeof(T); } private: T *ptr_; uptr cnt_; // Disallow evil constructors. InternalScopedBuffer(const InternalScopedBuffer&); void operator=(const InternalScopedBuffer&); }; class InternalScopedString : public InternalScopedBuffer { public: explicit InternalScopedString(uptr max_length) : InternalScopedBuffer(max_length), length_(0) { (*this)[0] = '\0'; } uptr length() { return length_; } void clear() { (*this)[0] = '\0'; length_ = 0; } void append(const char *format, ...); private: uptr length_; }; // Simple low-level (mmap-based) allocator for internal use. Doesn't have // constructor, so all instances of LowLevelAllocator should be // linker initialized. class LowLevelAllocator { public: // Requires an external lock. void *Allocate(uptr size); private: char *allocated_end_; char *allocated_current_; }; typedef void (*LowLevelAllocateCallback)(uptr ptr, uptr size); // Allows to register tool-specific callbacks for LowLevelAllocator. // Passing NULL removes the callback. void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback); // IO void RawWrite(const char *buffer); bool ColorizeReports(); void Printf(const char *format, ...); void Report(const char *format, ...); void SetPrintfAndReportCallback(void (*callback)(const char *)); #define VReport(level, ...) \ do { \ if ((uptr)Verbosity() >= (level)) Report(__VA_ARGS__); \ } while (0) #define VPrintf(level, ...) \ do { \ if ((uptr)Verbosity() >= (level)) Printf(__VA_ARGS__); \ } while (0) // Can be used to prevent mixing error reports from different sanitizers. extern StaticSpinMutex CommonSanitizerReportMutex; struct ReportFile { void Write(const char *buffer, uptr length); bool PrintsToTty(); void SetReportPath(const char *path); // Don't use fields directly. They are only declared public to allow // aggregate initialization. // Protects fields below. StaticSpinMutex *mu; // Opened file descriptor. Defaults to stderr. It may be equal to // kInvalidFd, in which case new file will be opened when necessary. fd_t fd; // Path prefix of report file, set via __sanitizer_set_report_path. char path_prefix[kMaxPathLength]; // Full path to report, obtained as .PID char full_path[kMaxPathLength]; // PID of the process that opened fd. If a fork() occurs, // the PID of child will be different from fd_pid. uptr fd_pid; private: void ReopenIfNecessary(); }; extern ReportFile report_file; extern uptr stoptheworld_tracer_pid; extern uptr stoptheworld_tracer_ppid; uptr OpenFile(const char *filename, bool write); // Opens the file 'file_name" and reads up to 'max_len' bytes. // The resulting buffer is mmaped and stored in '*buff'. // The size of the mmaped region is stored in '*buff_size', // Returns the number of read bytes or 0 if file can not be opened. uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, uptr max_len, int *errno_p = nullptr); // Maps given file to virtual memory, and returns pointer to it // (or NULL if the mapping failes). Stores the size of mmaped region // in '*buff_size'. void *MapFileToMemory(const char *file_name, uptr *buff_size); void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset); bool IsAccessibleMemoryRange(uptr beg, uptr size); // Error report formatting. const char *StripPathPrefix(const char *filepath, const char *strip_file_prefix); // Strip the directories from the module name. const char *StripModuleName(const char *module); // OS void DisableCoreDumperIfNecessary(); void DumpProcessMap(); bool FileExists(const char *filename); const char *GetEnv(const char *name); bool SetEnv(const char *name, const char *value); const char *GetPwd(); char *FindPathToBinary(const char *name); u32 GetUid(); void ReExec(); bool StackSizeIsUnlimited(); void SetStackSizeLimitInBytes(uptr limit); bool AddressSpaceIsUnlimited(); void SetAddressSpaceUnlimited(); void AdjustStackSize(void *attr); void PrepareForSandboxing(__sanitizer_sandbox_arguments *args); void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args); void SetSandboxingCallback(void (*f)()); void CoverageUpdateMapping(); void CovBeforeFork(); void CovAfterFork(int child_pid); void InitializeCoverage(bool enabled, const char *coverage_dir); void ReInitializeCoverage(bool enabled, const char *coverage_dir); void InitTlsSize(); uptr GetTlsSize(); // Other void SleepForSeconds(int seconds); void SleepForMillis(int millis); u64 NanoTime(); int Atexit(void (*function)(void)); void SortArray(uptr *array, uptr size); +bool TemplateMatch(const char *templ, const char *str); // Exit void NORETURN Abort(); void NORETURN Die(); void NORETURN CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2); // Set the name of the current thread to 'name', return true on succees. // The name may be truncated to a system-dependent limit. bool SanitizerSetThreadName(const char *name); // Get the name of the current thread (no more than max_len bytes), // return true on succees. name should have space for at least max_len+1 bytes. bool SanitizerGetThreadName(char *name, int max_len); // Specific tools may override behavior of "Die" and "CheckFailed" functions // to do tool-specific job. typedef void (*DieCallbackType)(void); void SetDieCallback(DieCallbackType); void SetUserDieCallback(DieCallbackType); DieCallbackType GetDieCallback(); typedef void (*CheckFailedCallbackType)(const char *, int, const char *, u64, u64); void SetCheckFailedCallback(CheckFailedCallbackType callback); // Callback will be called if soft_rss_limit_mb is given and the limit is // exceeded (exceeded==true) or if rss went down below the limit // (exceeded==false). // The callback should be registered once at the tool init time. void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)); // Functions related to signal handling. typedef void (*SignalHandlerType)(int, void *, void *); bool IsDeadlySignal(int signum); void InstallDeadlySignalHandlers(SignalHandlerType handler); // Alternative signal stack (POSIX-only). void SetAlternateSignalStack(); void UnsetAlternateSignalStack(); // We don't want a summary too long. const int kMaxSummaryLength = 1024; // Construct a one-line string: // SUMMARY: SanitizerToolName: error_message // and pass it to __sanitizer_report_error_summary. void ReportErrorSummary(const char *error_message); // Same as above, but construct error_message as: // error_type file:line function void ReportErrorSummary(const char *error_type, const char *file, int line, const char *function); void ReportErrorSummary(const char *error_type, StackTrace *trace); // Math #if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__) extern "C" { unsigned char _BitScanForward(unsigned long *index, unsigned long mask); // NOLINT unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); // NOLINT #if defined(_WIN64) unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask); // NOLINT unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); // NOLINT #endif } #endif INLINE uptr MostSignificantSetBitIndex(uptr x) { CHECK_NE(x, 0U); unsigned long up; // NOLINT #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(x); #elif defined(_WIN64) _BitScanReverse64(&up, x); #else _BitScanReverse(&up, x); #endif return up; } INLINE uptr LeastSignificantSetBitIndex(uptr x) { CHECK_NE(x, 0U); unsigned long up; // NOLINT #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) up = __builtin_ctzl(x); #elif defined(_WIN64) _BitScanForward64(&up, x); #else _BitScanForward(&up, x); #endif return up; } INLINE bool IsPowerOfTwo(uptr x) { return (x & (x - 1)) == 0; } INLINE uptr RoundUpToPowerOfTwo(uptr size) { CHECK(size); if (IsPowerOfTwo(size)) return size; uptr up = MostSignificantSetBitIndex(size); CHECK(size < (1ULL << (up + 1))); CHECK(size > (1ULL << up)); return 1UL << (up + 1); } INLINE uptr RoundUpTo(uptr size, uptr boundary) { CHECK(IsPowerOfTwo(boundary)); return (size + boundary - 1) & ~(boundary - 1); } INLINE uptr RoundDownTo(uptr x, uptr boundary) { return x & ~(boundary - 1); } INLINE bool IsAligned(uptr a, uptr alignment) { return (a & (alignment - 1)) == 0; } INLINE uptr Log2(uptr x) { CHECK(IsPowerOfTwo(x)); #if !SANITIZER_WINDOWS || defined(__clang__) || defined(__GNUC__) return __builtin_ctzl(x); #elif defined(_WIN64) unsigned long ret; // NOLINT _BitScanForward64(&ret, x); return ret; #else unsigned long ret; // NOLINT _BitScanForward(&ret, x); return ret; #endif } // Don't use std::min, std::max or std::swap, to minimize dependency // on libstdc++. template T Min(T a, T b) { return a < b ? a : b; } template T Max(T a, T b) { return a > b ? a : b; } template void Swap(T& a, T& b) { T tmp = a; a = b; b = tmp; } // Char handling INLINE bool IsSpace(int c) { return (c == ' ') || (c == '\n') || (c == '\t') || (c == '\f') || (c == '\r') || (c == '\v'); } INLINE bool IsDigit(int c) { return (c >= '0') && (c <= '9'); } INLINE int ToLower(int c) { return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c; } // A low-level vector based on mmap. May incur a significant memory overhead for // small vectors. // WARNING: The current implementation supports only POD types. template class InternalMmapVectorNoCtor { public: void Initialize(uptr initial_capacity) { capacity_ = Max(initial_capacity, (uptr)1); size_ = 0; data_ = (T *)MmapOrDie(capacity_ * sizeof(T), "InternalMmapVectorNoCtor"); } void Destroy() { UnmapOrDie(data_, capacity_ * sizeof(T)); } T &operator[](uptr i) { CHECK_LT(i, size_); return data_[i]; } const T &operator[](uptr i) const { CHECK_LT(i, size_); return data_[i]; } void push_back(const T &element) { CHECK_LE(size_, capacity_); if (size_ == capacity_) { uptr new_capacity = RoundUpToPowerOfTwo(size_ + 1); Resize(new_capacity); } data_[size_++] = element; } T &back() { CHECK_GT(size_, 0); return data_[size_ - 1]; } void pop_back() { CHECK_GT(size_, 0); size_--; } uptr size() const { return size_; } const T *data() const { return data_; } uptr capacity() const { return capacity_; } void clear() { size_ = 0; } private: void Resize(uptr new_capacity) { CHECK_GT(new_capacity, 0); CHECK_LE(size_, new_capacity); T *new_data = (T *)MmapOrDie(new_capacity * sizeof(T), "InternalMmapVector"); internal_memcpy(new_data, data_, size_ * sizeof(T)); T *old_data = data_; data_ = new_data; UnmapOrDie(old_data, capacity_ * sizeof(T)); capacity_ = new_capacity; } T *data_; uptr capacity_; uptr size_; }; template class InternalMmapVector : public InternalMmapVectorNoCtor { public: explicit InternalMmapVector(uptr initial_capacity) { InternalMmapVectorNoCtor::Initialize(initial_capacity); } ~InternalMmapVector() { InternalMmapVectorNoCtor::Destroy(); } // Disallow evil constructors. InternalMmapVector(const InternalMmapVector&); void operator=(const InternalMmapVector&); }; // HeapSort for arrays and InternalMmapVector. template void InternalSort(Container *v, uptr size, Compare comp) { if (size < 2) return; // Stage 1: insert elements to the heap. for (uptr i = 1; i < size; i++) { uptr j, p; for (j = i; j > 0; j = p) { p = (j - 1) / 2; if (comp((*v)[p], (*v)[j])) Swap((*v)[j], (*v)[p]); else break; } } // Stage 2: swap largest element with the last one, // and sink the new top. for (uptr i = size - 1; i > 0; i--) { Swap((*v)[0], (*v)[i]); uptr j, max_ind; for (j = 0; j < i; j = max_ind) { uptr left = 2 * j + 1; uptr right = 2 * j + 2; max_ind = j; if (left < i && comp((*v)[max_ind], (*v)[left])) max_ind = left; if (right < i && comp((*v)[max_ind], (*v)[right])) max_ind = right; if (max_ind != j) Swap((*v)[j], (*v)[max_ind]); else break; } } } template uptr InternalBinarySearch(const Container &v, uptr first, uptr last, const Value &val, Compare comp) { uptr not_found = last + 1; while (last >= first) { uptr mid = (first + last) / 2; if (comp(v[mid], val)) first = mid + 1; else if (comp(val, v[mid])) last = mid - 1; else return mid; } return not_found; } // Represents a binary loaded into virtual memory (e.g. this can be an // executable or a shared object). class LoadedModule { public: LoadedModule(const char *module_name, uptr base_address); void clear(); void addAddressRange(uptr beg, uptr end, bool executable); bool containsAddress(uptr address) const; const char *full_name() const { return full_name_; } uptr base_address() const { return base_address_; } struct AddressRange { AddressRange *next; uptr beg; uptr end; bool executable; AddressRange(uptr beg, uptr end, bool executable) : next(nullptr), beg(beg), end(end), executable(executable) {} }; typedef IntrusiveList::ConstIterator Iterator; Iterator ranges() const { return Iterator(&ranges_); } private: char *full_name_; // Owned. uptr base_address_; IntrusiveList ranges_; }; // OS-dependent function that fills array with descriptions of at most // "max_modules" currently loaded modules. Returns the number of // initialized modules. If filter is nonzero, ignores modules for which // filter(full_name) is false. typedef bool (*string_predicate_t)(const char *); uptr GetListOfModules(LoadedModule *modules, uptr max_modules, string_predicate_t filter); #if SANITIZER_POSIX const uptr kPthreadDestructorIterations = 4; #else // Unused on Windows. const uptr kPthreadDestructorIterations = 0; #endif // Callback type for iterating over a set of memory ranges. typedef void (*RangeIteratorCallback)(uptr begin, uptr end, void *arg); #if SANITIZER_ANDROID // Initialize Android logging. Any writes before this are silently lost. void AndroidLogInit(); void AndroidLogWrite(const char *buffer); void GetExtraActivationFlags(char *buf, uptr size); void SanitizerInitializeUnwinder(); #else INLINE void AndroidLogInit() {} INLINE void AndroidLogWrite(const char *buffer_unused) {} INLINE void GetExtraActivationFlags(char *buf, uptr size) { *buf = '\0'; } INLINE void SanitizerInitializeUnwinder() {} #endif void *internal_start_thread(void(*func)(void*), void *arg); void internal_join_thread(void *th); void MaybeStartBackgroudThread(); // Make the compiler think that something is going on there. // Use this inside a loop that looks like memset/memcpy/etc to prevent the // compiler from recognising it and turning it into an actual call to // memset/memcpy/etc. static inline void SanitizerBreakOptimization(void *arg) { #if _MSC_VER // FIXME: make sure this is actually enough. __asm; #else __asm__ __volatile__("" : : "r" (arg) : "memory"); #endif } } // namespace __sanitizer inline void *operator new(__sanitizer::operator_new_size_type size, __sanitizer::LowLevelAllocator &alloc) { return alloc.Allocate(size); } struct StackDepotStats { uptr n_uniq_ids; uptr allocated; }; #endif // SANITIZER_COMMON_H Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc (revision 279194) @@ -1,135 +1,135 @@ //===-- sanitizer_common_libcdep.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 shared between AddressSanitizer and ThreadSanitizer // run-time libraries. //===----------------------------------------------------------------------===// #include "sanitizer_common.h" #include "sanitizer_flags.h" #include "sanitizer_stackdepot.h" #include "sanitizer_stacktrace.h" #include "sanitizer_symbolizer.h" namespace __sanitizer { bool ReportFile::PrintsToTty() { SpinMutexLock l(mu); ReopenIfNecessary(); return internal_isatty(fd) != 0; } bool ColorizeReports() { // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color // printing on Windows. if (SANITIZER_WINDOWS) return false; const char *flag = common_flags()->color; return internal_strcmp(flag, "always") == 0 || (internal_strcmp(flag, "auto") == 0 && report_file.PrintsToTty()); } static void (*sandboxing_callback)(); void SetSandboxingCallback(void (*f)()) { sandboxing_callback = f; } void ReportErrorSummary(const char *error_type, StackTrace *stack) { if (!common_flags()->print_summary) return; #if !SANITIZER_GO if (stack->size > 0 && Symbolizer::GetOrInit()->CanReturnFileLineInfo()) { // Currently, we include the first stack frame into the report summary. // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); const AddressInfo &ai = frame->info; ReportErrorSummary(error_type, ai.file, ai.line, ai.function); frame->ClearAll(); } #else AddressInfo ai; ReportErrorSummary(error_type, ai.file, ai.line, ai.function); #endif } static void (*SoftRssLimitExceededCallback)(bool exceeded); void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) { CHECK_EQ(SoftRssLimitExceededCallback, nullptr); SoftRssLimitExceededCallback = Callback; } void BackgroundThread(void *arg) { uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb; uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb; uptr prev_reported_rss = 0; uptr prev_reported_stack_depot_size = 0; bool reached_soft_rss_limit = false; while (true) { SleepForMillis(100); uptr current_rss_mb = GetRSS() >> 20; if (Verbosity()) { // If RSS has grown 10% since last time, print some information. if (prev_reported_rss * 11 / 10 < current_rss_mb) { Printf("%s: RSS: %zdMb\n", SanitizerToolName, current_rss_mb); prev_reported_rss = current_rss_mb; } // If stack depot has grown 10% since last time, print it too. StackDepotStats *stack_depot_stats = StackDepotGetStats(); if (prev_reported_stack_depot_size * 11 / 10 < stack_depot_stats->allocated) { Printf("%s: StackDepot: %zd ids; %zdM allocated\n", SanitizerToolName, stack_depot_stats->n_uniq_ids, stack_depot_stats->allocated >> 20); prev_reported_stack_depot_size = stack_depot_stats->allocated; } } // Check RSS against the limit. if (hard_rss_limit_mb && hard_rss_limit_mb < current_rss_mb) { Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n", SanitizerToolName, hard_rss_limit_mb, current_rss_mb); DumpProcessMap(); Die(); } if (soft_rss_limit_mb) { if (soft_rss_limit_mb < current_rss_mb && !reached_soft_rss_limit) { reached_soft_rss_limit = true; Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n", SanitizerToolName, soft_rss_limit_mb, current_rss_mb); if (SoftRssLimitExceededCallback) SoftRssLimitExceededCallback(true); } else if (soft_rss_limit_mb >= current_rss_mb && reached_soft_rss_limit) { reached_soft_rss_limit = false; if (SoftRssLimitExceededCallback) SoftRssLimitExceededCallback(false); } } } } void MaybeStartBackgroudThread() { if (!SANITIZER_LINUX) return; // Need to implement/test on other platforms. // Start the background thread if one of the rss limits is given. if (!common_flags()->hard_rss_limit_mb && !common_flags()->soft_rss_limit_mb) return; - if (!real_pthread_create) return; // Can't spawn the thread anyway. + if (!&real_pthread_create) return; // Can't spawn the thread anyway. internal_start_thread(BackgroundThread, nullptr); } } // namespace __sanitizer void NOINLINE __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) { PrepareForSandboxing(args); if (sandboxing_callback) sandboxing_callback(); } Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common_syscalls.inc (revision 279194) @@ -1,2850 +1,2852 @@ //===-- sanitizer_common_syscalls.inc ---------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Common syscalls handlers for tools like AddressSanitizer, // ThreadSanitizer, MemorySanitizer, etc. // // This file should be included into the tool's interceptor file, // which has to define it's own macros: // COMMON_SYSCALL_PRE_READ_RANGE // Called in prehook for regions that will be read by the kernel and // must be initialized. // COMMON_SYSCALL_PRE_WRITE_RANGE // Called in prehook for regions that will be written to by the kernel // and must be addressable. The actual write range may be smaller than // reported in the prehook. See POST_WRITE_RANGE. // COMMON_SYSCALL_POST_READ_RANGE // Called in posthook for regions that were read by the kernel. Does // not make much sense. // COMMON_SYSCALL_POST_WRITE_RANGE // Called in posthook for regions that were written to by the kernel // and are now initialized. // COMMON_SYSCALL_ACQUIRE(addr) // Acquire memory visibility from addr. // COMMON_SYSCALL_RELEASE(addr) // Release memory visibility to addr. // COMMON_SYSCALL_FD_CLOSE(fd) // Called before closing file descriptor fd. // COMMON_SYSCALL_FD_ACQUIRE(fd) // Acquire memory visibility from fd. // COMMON_SYSCALL_FD_RELEASE(fd) // Release memory visibility to fd. // COMMON_SYSCALL_PRE_FORK() // Called before fork syscall. // COMMON_SYSCALL_POST_FORK(long res) // Called after fork syscall. //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" #if SANITIZER_LINUX #include "sanitizer_libc.h" #define PRE_SYSCALL(name) \ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name #define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s) #define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) #define POST_SYSCALL(name) \ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_impl_##name #define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s) #define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s) #ifndef COMMON_SYSCALL_ACQUIRE # define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr)) #endif #ifndef COMMON_SYSCALL_RELEASE # define COMMON_SYSCALL_RELEASE(addr) ((void)(addr)) #endif #ifndef COMMON_SYSCALL_FD_CLOSE # define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd)) #endif #ifndef COMMON_SYSCALL_FD_ACQUIRE # define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd)) #endif #ifndef COMMON_SYSCALL_FD_RELEASE # define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd)) #endif #ifndef COMMON_SYSCALL_PRE_FORK # define COMMON_SYSCALL_PRE_FORK() {} #endif #ifndef COMMON_SYSCALL_POST_FORK # define COMMON_SYSCALL_POST_FORK(res) {} #endif // FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such). extern "C" { struct sanitizer_kernel_iovec { void *iov_base; unsigned long iov_len; }; struct sanitizer_kernel_msghdr { void *msg_name; int msg_namelen; struct sanitizer_kernel_iovec *msg_iov; unsigned long msg_iovlen; void *msg_control; unsigned long msg_controllen; unsigned msg_flags; }; struct sanitizer_kernel_mmsghdr { struct sanitizer_kernel_msghdr msg_hdr; unsigned msg_len; }; struct sanitizer_kernel_timespec { long tv_sec; long tv_nsec; }; struct sanitizer_kernel_timeval { long tv_sec; long tv_usec; }; struct sanitizer_kernel_rusage { struct sanitizer_kernel_timeval ru_timeval[2]; long ru_long[14]; }; struct sanitizer_kernel_sockaddr { unsigned short sa_family; char sa_data[14]; }; // Real sigset size is always passed as a syscall argument. // Declare it "void" to catch sizeof(kernel_sigset_t). typedef void kernel_sigset_t; static void kernel_write_iovec(const __sanitizer_iovec *iovec, SIZE_T iovlen, SIZE_T maxlen) { for (SIZE_T i = 0; i < iovlen && maxlen; ++i) { SSIZE_T sz = Min(iovec[i].iov_len, maxlen); POST_WRITE(iovec[i].iov_base, sz); maxlen -= sz; } } // This functions uses POST_READ, because it needs to run after syscall to know // the real read range. static void kernel_read_iovec(const __sanitizer_iovec *iovec, SIZE_T iovlen, SIZE_T maxlen) { POST_READ(iovec, sizeof(*iovec) * iovlen); for (SIZE_T i = 0; i < iovlen && maxlen; ++i) { SSIZE_T sz = Min(iovec[i].iov_len, maxlen); POST_READ(iovec[i].iov_base, sz); maxlen -= sz; } } PRE_SYSCALL(recvmsg)(long sockfd, sanitizer_kernel_msghdr *msg, long flags) { PRE_READ(msg, sizeof(*msg)); } POST_SYSCALL(recvmsg)(long res, long sockfd, sanitizer_kernel_msghdr *msg, long flags) { if (res >= 0) { if (msg) { for (unsigned long i = 0; i < msg->msg_iovlen; ++i) { POST_WRITE(msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); } POST_WRITE(msg->msg_control, msg->msg_controllen); } } } PRE_SYSCALL(recvmmsg)(long fd, sanitizer_kernel_mmsghdr *msg, long vlen, long flags, void *timeout) { PRE_READ(msg, vlen * sizeof(*msg)); } POST_SYSCALL(recvmmsg)(long res, long fd, sanitizer_kernel_mmsghdr *msg, long vlen, long flags, void *timeout) { if (res >= 0) { if (msg) { for (unsigned long i = 0; i < msg->msg_hdr.msg_iovlen; ++i) { POST_WRITE(msg->msg_hdr.msg_iov[i].iov_base, msg->msg_hdr.msg_iov[i].iov_len); } POST_WRITE(msg->msg_hdr.msg_control, msg->msg_hdr.msg_controllen); POST_WRITE(&msg->msg_len, sizeof(msg->msg_len)); } if (timeout) POST_WRITE(timeout, struct_timespec_sz); } } PRE_SYSCALL(read)(long fd, void *buf, uptr count) { if (buf) { PRE_WRITE(buf, count); } } POST_SYSCALL(read)(long res, long fd, void *buf, uptr count) { if (res > 0 && buf) { POST_WRITE(buf, res); } } PRE_SYSCALL(time)(void *tloc) {} POST_SYSCALL(time)(long res, void *tloc) { if (res >= 0) { if (tloc) POST_WRITE(tloc, sizeof(long)); } } PRE_SYSCALL(stime)(void *tptr) {} POST_SYSCALL(stime)(long res, void *tptr) { if (res >= 0) { if (tptr) POST_WRITE(tptr, sizeof(long)); } } PRE_SYSCALL(gettimeofday)(void *tv, void *tz) {} POST_SYSCALL(gettimeofday)(long res, void *tv, void *tz) { if (res >= 0) { if (tv) POST_WRITE(tv, timeval_sz); if (tz) POST_WRITE(tz, struct_timezone_sz); } } PRE_SYSCALL(settimeofday)(void *tv, void *tz) {} POST_SYSCALL(settimeofday)(long res, void *tv, void *tz) { if (res >= 0) { if (tv) POST_WRITE(tv, timeval_sz); if (tz) POST_WRITE(tz, struct_timezone_sz); } } #if !SANITIZER_ANDROID PRE_SYSCALL(adjtimex)(void *txc_p) {} POST_SYSCALL(adjtimex)(long res, void *txc_p) { if (res >= 0) { if (txc_p) POST_WRITE(txc_p, struct_timex_sz); } } #endif PRE_SYSCALL(times)(void *tbuf) {} POST_SYSCALL(times)(long res, void *tbuf) { if (res >= 0) { if (tbuf) POST_WRITE(tbuf, struct_tms_sz); } } PRE_SYSCALL(gettid)() {} POST_SYSCALL(gettid)(long res) {} PRE_SYSCALL(nanosleep)(void *rqtp, void *rmtp) {} POST_SYSCALL(nanosleep)(long res, void *rqtp, void *rmtp) { if (res >= 0) { if (rqtp) POST_WRITE(rqtp, struct_timespec_sz); if (rmtp) POST_WRITE(rmtp, struct_timespec_sz); } } PRE_SYSCALL(alarm)(long seconds) {} POST_SYSCALL(alarm)(long res, long seconds) {} PRE_SYSCALL(getpid)() {} POST_SYSCALL(getpid)(long res) {} PRE_SYSCALL(getppid)() {} POST_SYSCALL(getppid)(long res) {} PRE_SYSCALL(getuid)() {} POST_SYSCALL(getuid)(long res) {} PRE_SYSCALL(geteuid)() {} POST_SYSCALL(geteuid)(long res) {} PRE_SYSCALL(getgid)() {} POST_SYSCALL(getgid)(long res) {} PRE_SYSCALL(getegid)() {} POST_SYSCALL(getegid)(long res) {} PRE_SYSCALL(getresuid)(void *ruid, void *euid, void *suid) {} POST_SYSCALL(getresuid)(long res, void *ruid, void *euid, void *suid) { if (res >= 0) { if (ruid) POST_WRITE(ruid, sizeof(unsigned)); if (euid) POST_WRITE(euid, sizeof(unsigned)); if (suid) POST_WRITE(suid, sizeof(unsigned)); } } PRE_SYSCALL(getresgid)(void *rgid, void *egid, void *sgid) {} POST_SYSCALL(getresgid)(long res, void *rgid, void *egid, void *sgid) { if (res >= 0) { if (rgid) POST_WRITE(rgid, sizeof(unsigned)); if (egid) POST_WRITE(egid, sizeof(unsigned)); if (sgid) POST_WRITE(sgid, sizeof(unsigned)); } } PRE_SYSCALL(getpgid)(long pid) {} POST_SYSCALL(getpgid)(long res, long pid) {} PRE_SYSCALL(getpgrp)() {} POST_SYSCALL(getpgrp)(long res) {} PRE_SYSCALL(getsid)(long pid) {} POST_SYSCALL(getsid)(long res, long pid) {} PRE_SYSCALL(getgroups)(long gidsetsize, void *grouplist) {} POST_SYSCALL(getgroups)(long res, long gidsetsize, __sanitizer___kernel_gid_t *grouplist) { if (res >= 0) { if (grouplist) POST_WRITE(grouplist, res * sizeof(*grouplist)); } } PRE_SYSCALL(setregid)(long rgid, long egid) {} POST_SYSCALL(setregid)(long res, long rgid, long egid) {} PRE_SYSCALL(setgid)(long gid) {} POST_SYSCALL(setgid)(long res, long gid) {} PRE_SYSCALL(setreuid)(long ruid, long euid) {} POST_SYSCALL(setreuid)(long res, long ruid, long euid) {} PRE_SYSCALL(setuid)(long uid) {} POST_SYSCALL(setuid)(long res, long uid) {} PRE_SYSCALL(setresuid)(long ruid, long euid, long suid) {} POST_SYSCALL(setresuid)(long res, long ruid, long euid, long suid) {} PRE_SYSCALL(setresgid)(long rgid, long egid, long sgid) {} POST_SYSCALL(setresgid)(long res, long rgid, long egid, long sgid) {} PRE_SYSCALL(setfsuid)(long uid) {} POST_SYSCALL(setfsuid)(long res, long uid) {} PRE_SYSCALL(setfsgid)(long gid) {} POST_SYSCALL(setfsgid)(long res, long gid) {} PRE_SYSCALL(setpgid)(long pid, long pgid) {} POST_SYSCALL(setpgid)(long res, long pid, long pgid) {} PRE_SYSCALL(setsid)() {} POST_SYSCALL(setsid)(long res) {} PRE_SYSCALL(setgroups)(long gidsetsize, __sanitizer___kernel_gid_t *grouplist) { if (grouplist) POST_WRITE(grouplist, gidsetsize * sizeof(*grouplist)); } POST_SYSCALL(setgroups)(long res, long gidsetsize, __sanitizer___kernel_gid_t *grouplist) {} PRE_SYSCALL(acct)(const void *name) { if (name) PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); } POST_SYSCALL(acct)(long res, const void *name) {} PRE_SYSCALL(capget)(void *header, void *dataptr) { if (header) PRE_READ(header, __user_cap_header_struct_sz); } POST_SYSCALL(capget)(long res, void *header, void *dataptr) { if (res >= 0) if (dataptr) POST_WRITE(dataptr, __user_cap_data_struct_sz); } PRE_SYSCALL(capset)(void *header, const void *data) { if (header) PRE_READ(header, __user_cap_header_struct_sz); if (data) PRE_READ(data, __user_cap_data_struct_sz); } POST_SYSCALL(capset)(long res, void *header, const void *data) {} PRE_SYSCALL(personality)(long personality) {} POST_SYSCALL(personality)(long res, long personality) {} PRE_SYSCALL(sigpending)(void *set) {} POST_SYSCALL(sigpending)(long res, void *set) { if (res >= 0) { if (set) POST_WRITE(set, old_sigset_t_sz); } } PRE_SYSCALL(sigprocmask)(long how, void *set, void *oset) {} POST_SYSCALL(sigprocmask)(long res, long how, void *set, void *oset) { if (res >= 0) { if (set) POST_WRITE(set, old_sigset_t_sz); if (oset) POST_WRITE(oset, old_sigset_t_sz); } } PRE_SYSCALL(getitimer)(long which, void *value) {} POST_SYSCALL(getitimer)(long res, long which, void *value) { if (res >= 0) { if (value) POST_WRITE(value, struct_itimerval_sz); } } PRE_SYSCALL(setitimer)(long which, void *value, void *ovalue) {} POST_SYSCALL(setitimer)(long res, long which, void *value, void *ovalue) { if (res >= 0) { if (value) POST_WRITE(value, struct_itimerval_sz); if (ovalue) POST_WRITE(ovalue, struct_itimerval_sz); } } PRE_SYSCALL(timer_create)(long which_clock, void *timer_event_spec, void *created_timer_id) {} POST_SYSCALL(timer_create)(long res, long which_clock, void *timer_event_spec, void *created_timer_id) { if (res >= 0) { if (timer_event_spec) POST_WRITE(timer_event_spec, struct_sigevent_sz); if (created_timer_id) POST_WRITE(created_timer_id, sizeof(long)); } } PRE_SYSCALL(timer_gettime)(long timer_id, void *setting) {} POST_SYSCALL(timer_gettime)(long res, long timer_id, void *setting) { if (res >= 0) { if (setting) POST_WRITE(setting, struct_itimerspec_sz); } } PRE_SYSCALL(timer_getoverrun)(long timer_id) {} POST_SYSCALL(timer_getoverrun)(long res, long timer_id) {} PRE_SYSCALL(timer_settime)(long timer_id, long flags, const void *new_setting, void *old_setting) { if (new_setting) PRE_READ(new_setting, struct_itimerspec_sz); } POST_SYSCALL(timer_settime)(long res, long timer_id, long flags, const void *new_setting, void *old_setting) { if (res >= 0) { if (old_setting) POST_WRITE(old_setting, struct_itimerspec_sz); } } PRE_SYSCALL(timer_delete)(long timer_id) {} POST_SYSCALL(timer_delete)(long res, long timer_id) {} PRE_SYSCALL(clock_settime)(long which_clock, const void *tp) { if (tp) PRE_READ(tp, struct_timespec_sz); } POST_SYSCALL(clock_settime)(long res, long which_clock, const void *tp) {} PRE_SYSCALL(clock_gettime)(long which_clock, void *tp) {} POST_SYSCALL(clock_gettime)(long res, long which_clock, void *tp) { if (res >= 0) { if (tp) POST_WRITE(tp, struct_timespec_sz); } } #if !SANITIZER_ANDROID PRE_SYSCALL(clock_adjtime)(long which_clock, void *tx) {} POST_SYSCALL(clock_adjtime)(long res, long which_clock, void *tx) { if (res >= 0) { if (tx) POST_WRITE(tx, struct_timex_sz); } } #endif PRE_SYSCALL(clock_getres)(long which_clock, void *tp) {} POST_SYSCALL(clock_getres)(long res, long which_clock, void *tp) { if (res >= 0) { if (tp) POST_WRITE(tp, struct_timespec_sz); } } PRE_SYSCALL(clock_nanosleep)(long which_clock, long flags, const void *rqtp, void *rmtp) { if (rqtp) PRE_READ(rqtp, struct_timespec_sz); } POST_SYSCALL(clock_nanosleep)(long res, long which_clock, long flags, const void *rqtp, void *rmtp) { if (res >= 0) { if (rmtp) POST_WRITE(rmtp, struct_timespec_sz); } } PRE_SYSCALL(nice)(long increment) {} POST_SYSCALL(nice)(long res, long increment) {} PRE_SYSCALL(sched_setscheduler)(long pid, long policy, void *param) {} POST_SYSCALL(sched_setscheduler)(long res, long pid, long policy, void *param) { if (res >= 0) { if (param) POST_WRITE(param, struct_sched_param_sz); } } PRE_SYSCALL(sched_setparam)(long pid, void *param) { if (param) PRE_READ(param, struct_sched_param_sz); } POST_SYSCALL(sched_setparam)(long res, long pid, void *param) {} PRE_SYSCALL(sched_getscheduler)(long pid) {} POST_SYSCALL(sched_getscheduler)(long res, long pid) {} PRE_SYSCALL(sched_getparam)(long pid, void *param) {} POST_SYSCALL(sched_getparam)(long res, long pid, void *param) { if (res >= 0) { if (param) POST_WRITE(param, struct_sched_param_sz); } } PRE_SYSCALL(sched_setaffinity)(long pid, long len, void *user_mask_ptr) { if (user_mask_ptr) PRE_READ(user_mask_ptr, len); } POST_SYSCALL(sched_setaffinity)(long res, long pid, long len, void *user_mask_ptr) {} PRE_SYSCALL(sched_getaffinity)(long pid, long len, void *user_mask_ptr) {} POST_SYSCALL(sched_getaffinity)(long res, long pid, long len, void *user_mask_ptr) { if (res >= 0) { if (user_mask_ptr) POST_WRITE(user_mask_ptr, len); } } PRE_SYSCALL(sched_yield)() {} POST_SYSCALL(sched_yield)(long res) {} PRE_SYSCALL(sched_get_priority_max)(long policy) {} POST_SYSCALL(sched_get_priority_max)(long res, long policy) {} PRE_SYSCALL(sched_get_priority_min)(long policy) {} POST_SYSCALL(sched_get_priority_min)(long res, long policy) {} PRE_SYSCALL(sched_rr_get_interval)(long pid, void *interval) {} POST_SYSCALL(sched_rr_get_interval)(long res, long pid, void *interval) { if (res >= 0) { if (interval) POST_WRITE(interval, struct_timespec_sz); } } PRE_SYSCALL(setpriority)(long which, long who, long niceval) {} POST_SYSCALL(setpriority)(long res, long which, long who, long niceval) {} PRE_SYSCALL(getpriority)(long which, long who) {} POST_SYSCALL(getpriority)(long res, long which, long who) {} PRE_SYSCALL(shutdown)(long arg0, long arg1) {} POST_SYSCALL(shutdown)(long res, long arg0, long arg1) {} PRE_SYSCALL(reboot)(long magic1, long magic2, long cmd, void *arg) {} POST_SYSCALL(reboot)(long res, long magic1, long magic2, long cmd, void *arg) {} PRE_SYSCALL(restart_syscall)() {} POST_SYSCALL(restart_syscall)(long res) {} PRE_SYSCALL(kexec_load)(long entry, long nr_segments, void *segments, long flags) {} POST_SYSCALL(kexec_load)(long res, long entry, long nr_segments, void *segments, long flags) { if (res >= 0) { if (segments) POST_WRITE(segments, struct_kexec_segment_sz); } } PRE_SYSCALL(exit)(long error_code) {} POST_SYSCALL(exit)(long res, long error_code) {} PRE_SYSCALL(exit_group)(long error_code) {} POST_SYSCALL(exit_group)(long res, long error_code) {} PRE_SYSCALL(wait4)(long pid, void *stat_addr, long options, void *ru) {} POST_SYSCALL(wait4)(long res, long pid, void *stat_addr, long options, void *ru) { if (res >= 0) { if (stat_addr) POST_WRITE(stat_addr, sizeof(int)); if (ru) POST_WRITE(ru, struct_rusage_sz); } } PRE_SYSCALL(waitid)(long which, long pid, void *infop, long options, void *ru) { } POST_SYSCALL(waitid)(long res, long which, long pid, void *infop, long options, void *ru) { if (res >= 0) { if (infop) POST_WRITE(infop, siginfo_t_sz); if (ru) POST_WRITE(ru, struct_rusage_sz); } } PRE_SYSCALL(waitpid)(long pid, void *stat_addr, long options) {} POST_SYSCALL(waitpid)(long res, long pid, void *stat_addr, long options) { if (res >= 0) { if (stat_addr) POST_WRITE(stat_addr, sizeof(int)); } } PRE_SYSCALL(set_tid_address)(void *tidptr) {} POST_SYSCALL(set_tid_address)(long res, void *tidptr) { if (res >= 0) { if (tidptr) POST_WRITE(tidptr, sizeof(int)); } } PRE_SYSCALL(init_module)(void *umod, long len, const void *uargs) { if (uargs) PRE_READ(uargs, __sanitizer::internal_strlen((const char *)uargs) + 1); } POST_SYSCALL(init_module)(long res, void *umod, long len, const void *uargs) {} PRE_SYSCALL(delete_module)(const void *name_user, long flags) { if (name_user) PRE_READ(name_user, __sanitizer::internal_strlen((const char *)name_user) + 1); } POST_SYSCALL(delete_module)(long res, const void *name_user, long flags) {} PRE_SYSCALL(rt_sigprocmask)(long how, void *set, void *oset, long sigsetsize) {} POST_SYSCALL(rt_sigprocmask)(long res, long how, kernel_sigset_t *set, kernel_sigset_t *oset, long sigsetsize) { if (res >= 0) { if (set) POST_WRITE(set, sigsetsize); if (oset) POST_WRITE(oset, sigsetsize); } } PRE_SYSCALL(rt_sigpending)(void *set, long sigsetsize) {} POST_SYSCALL(rt_sigpending)(long res, kernel_sigset_t *set, long sigsetsize) { if (res >= 0) { if (set) POST_WRITE(set, sigsetsize); } } PRE_SYSCALL(rt_sigtimedwait)(const kernel_sigset_t *uthese, void *uinfo, const void *uts, long sigsetsize) { if (uthese) PRE_READ(uthese, sigsetsize); if (uts) PRE_READ(uts, struct_timespec_sz); } POST_SYSCALL(rt_sigtimedwait)(long res, const void *uthese, void *uinfo, const void *uts, long sigsetsize) { if (res >= 0) { if (uinfo) POST_WRITE(uinfo, siginfo_t_sz); } } PRE_SYSCALL(rt_tgsigqueueinfo)(long tgid, long pid, long sig, void *uinfo) {} POST_SYSCALL(rt_tgsigqueueinfo)(long res, long tgid, long pid, long sig, void *uinfo) { if (res >= 0) { if (uinfo) POST_WRITE(uinfo, siginfo_t_sz); } } PRE_SYSCALL(kill)(long pid, long sig) {} POST_SYSCALL(kill)(long res, long pid, long sig) {} PRE_SYSCALL(tgkill)(long tgid, long pid, long sig) {} POST_SYSCALL(tgkill)(long res, long tgid, long pid, long sig) {} PRE_SYSCALL(tkill)(long pid, long sig) {} POST_SYSCALL(tkill)(long res, long pid, long sig) {} PRE_SYSCALL(rt_sigqueueinfo)(long pid, long sig, void *uinfo) {} POST_SYSCALL(rt_sigqueueinfo)(long res, long pid, long sig, void *uinfo) { if (res >= 0) { if (uinfo) POST_WRITE(uinfo, siginfo_t_sz); } } PRE_SYSCALL(sgetmask)() {} POST_SYSCALL(sgetmask)(long res) {} PRE_SYSCALL(ssetmask)(long newmask) {} POST_SYSCALL(ssetmask)(long res, long newmask) {} PRE_SYSCALL(signal)(long sig, long handler) {} POST_SYSCALL(signal)(long res, long sig, long handler) {} PRE_SYSCALL(pause)() {} POST_SYSCALL(pause)(long res) {} PRE_SYSCALL(sync)() {} POST_SYSCALL(sync)(long res) {} PRE_SYSCALL(fsync)(long fd) {} POST_SYSCALL(fsync)(long res, long fd) {} PRE_SYSCALL(fdatasync)(long fd) {} POST_SYSCALL(fdatasync)(long res, long fd) {} PRE_SYSCALL(bdflush)(long func, long data) {} POST_SYSCALL(bdflush)(long res, long func, long data) {} PRE_SYSCALL(mount)(void *dev_name, void *dir_name, void *type, long flags, void *data) {} POST_SYSCALL(mount)(long res, void *dev_name, void *dir_name, void *type, long flags, void *data) { if (res >= 0) { if (dev_name) POST_WRITE(dev_name, __sanitizer::internal_strlen((const char *)dev_name) + 1); if (dir_name) POST_WRITE(dir_name, __sanitizer::internal_strlen((const char *)dir_name) + 1); if (type) POST_WRITE(type, __sanitizer::internal_strlen((const char *)type) + 1); } } PRE_SYSCALL(umount)(void *name, long flags) {} POST_SYSCALL(umount)(long res, void *name, long flags) { if (res >= 0) { if (name) POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); } } PRE_SYSCALL(oldumount)(void *name) {} POST_SYSCALL(oldumount)(long res, void *name) { if (res >= 0) { if (name) POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); } } PRE_SYSCALL(truncate)(const void *path, long length) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); } POST_SYSCALL(truncate)(long res, const void *path, long length) {} PRE_SYSCALL(ftruncate)(long fd, long length) {} POST_SYSCALL(ftruncate)(long res, long fd, long length) {} PRE_SYSCALL(stat)(const void *filename, void *statbuf) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(stat)(long res, const void *filename, void *statbuf) { if (res >= 0) { if (statbuf) POST_WRITE(statbuf, struct___old_kernel_stat_sz); } } #if !SANITIZER_ANDROID PRE_SYSCALL(statfs)(const void *path, void *buf) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); } POST_SYSCALL(statfs)(long res, const void *path, void *buf) { if (res >= 0) { if (buf) POST_WRITE(buf, struct_statfs_sz); } } PRE_SYSCALL(statfs64)(const void *path, long sz, void *buf) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); } POST_SYSCALL(statfs64)(long res, const void *path, long sz, void *buf) { if (res >= 0) { if (buf) POST_WRITE(buf, struct_statfs64_sz); } } PRE_SYSCALL(fstatfs)(long fd, void *buf) {} POST_SYSCALL(fstatfs)(long res, long fd, void *buf) { if (res >= 0) { if (buf) POST_WRITE(buf, struct_statfs_sz); } } PRE_SYSCALL(fstatfs64)(long fd, long sz, void *buf) {} POST_SYSCALL(fstatfs64)(long res, long fd, long sz, void *buf) { if (res >= 0) { if (buf) POST_WRITE(buf, struct_statfs64_sz); } } #endif // !SANITIZER_ANDROID PRE_SYSCALL(lstat)(const void *filename, void *statbuf) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(lstat)(long res, const void *filename, void *statbuf) { if (res >= 0) { if (statbuf) POST_WRITE(statbuf, struct___old_kernel_stat_sz); } } PRE_SYSCALL(fstat)(long fd, void *statbuf) {} POST_SYSCALL(fstat)(long res, long fd, void *statbuf) { if (res >= 0) { if (statbuf) POST_WRITE(statbuf, struct___old_kernel_stat_sz); } } PRE_SYSCALL(newstat)(const void *filename, void *statbuf) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(newstat)(long res, const void *filename, void *statbuf) { if (res >= 0) { if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz); } } PRE_SYSCALL(newlstat)(const void *filename, void *statbuf) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(newlstat)(long res, const void *filename, void *statbuf) { if (res >= 0) { if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz); } } PRE_SYSCALL(newfstat)(long fd, void *statbuf) {} POST_SYSCALL(newfstat)(long res, long fd, void *statbuf) { if (res >= 0) { if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz); } } #if !SANITIZER_ANDROID PRE_SYSCALL(ustat)(long dev, void *ubuf) {} POST_SYSCALL(ustat)(long res, long dev, void *ubuf) { if (res >= 0) { if (ubuf) POST_WRITE(ubuf, struct_ustat_sz); } } #endif // !SANITIZER_ANDROID PRE_SYSCALL(stat64)(const void *filename, void *statbuf) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(stat64)(long res, const void *filename, void *statbuf) { if (res >= 0) { if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz); } } PRE_SYSCALL(fstat64)(long fd, void *statbuf) {} POST_SYSCALL(fstat64)(long res, long fd, void *statbuf) { if (res >= 0) { if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz); } } PRE_SYSCALL(lstat64)(const void *filename, void *statbuf) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(lstat64)(long res, const void *filename, void *statbuf) { if (res >= 0) { if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz); } } PRE_SYSCALL(setxattr)(const void *path, const void *name, const void *value, long size, long flags) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); if (name) PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); if (value) PRE_READ(value, size); } POST_SYSCALL(setxattr)(long res, const void *path, const void *name, const void *value, long size, long flags) {} PRE_SYSCALL(lsetxattr)(const void *path, const void *name, const void *value, long size, long flags) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); if (name) PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); if (value) PRE_READ(value, size); } POST_SYSCALL(lsetxattr)(long res, const void *path, const void *name, const void *value, long size, long flags) {} PRE_SYSCALL(fsetxattr)(long fd, const void *name, const void *value, long size, long flags) { if (name) PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); if (value) PRE_READ(value, size); } POST_SYSCALL(fsetxattr)(long res, long fd, const void *name, const void *value, long size, long flags) {} PRE_SYSCALL(getxattr)(const void *path, const void *name, void *value, long size) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); if (name) PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); } POST_SYSCALL(getxattr)(long res, const void *path, const void *name, void *value, long size) { if (size && res > 0) { if (value) POST_WRITE(value, res); } } PRE_SYSCALL(lgetxattr)(const void *path, const void *name, void *value, long size) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); if (name) PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); } POST_SYSCALL(lgetxattr)(long res, const void *path, const void *name, void *value, long size) { if (size && res > 0) { if (value) POST_WRITE(value, res); } } PRE_SYSCALL(fgetxattr)(long fd, const void *name, void *value, long size) { if (name) PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); } POST_SYSCALL(fgetxattr)(long res, long fd, const void *name, void *value, long size) { if (size && res > 0) { if (value) POST_WRITE(value, res); } } PRE_SYSCALL(listxattr)(const void *path, void *list, long size) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); } POST_SYSCALL(listxattr)(long res, const void *path, void *list, long size) { if (size && res > 0) { if (list) POST_WRITE(list, res); } } PRE_SYSCALL(llistxattr)(const void *path, void *list, long size) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); } POST_SYSCALL(llistxattr)(long res, const void *path, void *list, long size) { if (size && res > 0) { if (list) POST_WRITE(list, res); } } PRE_SYSCALL(flistxattr)(long fd, void *list, long size) {} POST_SYSCALL(flistxattr)(long res, long fd, void *list, long size) { if (size && res > 0) { if (list) POST_WRITE(list, res); } } PRE_SYSCALL(removexattr)(const void *path, const void *name) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); if (name) PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); } POST_SYSCALL(removexattr)(long res, const void *path, const void *name) {} PRE_SYSCALL(lremovexattr)(const void *path, const void *name) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); if (name) PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); } POST_SYSCALL(lremovexattr)(long res, const void *path, const void *name) {} PRE_SYSCALL(fremovexattr)(long fd, const void *name) { if (name) PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); } POST_SYSCALL(fremovexattr)(long res, long fd, const void *name) {} PRE_SYSCALL(brk)(long brk) {} POST_SYSCALL(brk)(long res, long brk) {} PRE_SYSCALL(mprotect)(long start, long len, long prot) {} POST_SYSCALL(mprotect)(long res, long start, long len, long prot) {} PRE_SYSCALL(mremap)(long addr, long old_len, long new_len, long flags, long new_addr) {} POST_SYSCALL(mremap)(long res, long addr, long old_len, long new_len, long flags, long new_addr) {} PRE_SYSCALL(remap_file_pages)(long start, long size, long prot, long pgoff, long flags) {} POST_SYSCALL(remap_file_pages)(long res, long start, long size, long prot, long pgoff, long flags) {} PRE_SYSCALL(msync)(long start, long len, long flags) {} POST_SYSCALL(msync)(long res, long start, long len, long flags) {} PRE_SYSCALL(munmap)(long addr, long len) {} POST_SYSCALL(munmap)(long res, long addr, long len) {} PRE_SYSCALL(mlock)(long start, long len) {} POST_SYSCALL(mlock)(long res, long start, long len) {} PRE_SYSCALL(munlock)(long start, long len) {} POST_SYSCALL(munlock)(long res, long start, long len) {} PRE_SYSCALL(mlockall)(long flags) {} POST_SYSCALL(mlockall)(long res, long flags) {} PRE_SYSCALL(munlockall)() {} POST_SYSCALL(munlockall)(long res) {} PRE_SYSCALL(madvise)(long start, long len, long behavior) {} POST_SYSCALL(madvise)(long res, long start, long len, long behavior) {} PRE_SYSCALL(mincore)(long start, long len, void *vec) {} POST_SYSCALL(mincore)(long res, long start, long len, void *vec) { if (res >= 0) { if (vec) { POST_WRITE(vec, (len + GetPageSizeCached() - 1) / GetPageSizeCached()); } } } PRE_SYSCALL(pivot_root)(const void *new_root, const void *put_old) { if (new_root) PRE_READ(new_root, __sanitizer::internal_strlen((const char *)new_root) + 1); if (put_old) PRE_READ(put_old, __sanitizer::internal_strlen((const char *)put_old) + 1); } POST_SYSCALL(pivot_root)(long res, const void *new_root, const void *put_old) {} PRE_SYSCALL(chroot)(const void *filename) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(chroot)(long res, const void *filename) {} PRE_SYSCALL(mknod)(const void *filename, long mode, long dev) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(mknod)(long res, const void *filename, long mode, long dev) {} PRE_SYSCALL(link)(const void *oldname, const void *newname) { if (oldname) PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); if (newname) PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); } POST_SYSCALL(link)(long res, const void *oldname, const void *newname) {} PRE_SYSCALL(symlink)(const void *old, const void *new_) { if (old) PRE_READ(old, __sanitizer::internal_strlen((const char *)old) + 1); if (new_) PRE_READ(new_, __sanitizer::internal_strlen((const char *)new_) + 1); } POST_SYSCALL(symlink)(long res, const void *old, const void *new_) {} PRE_SYSCALL(unlink)(const void *pathname) { if (pathname) PRE_READ(pathname, __sanitizer::internal_strlen((const char *)pathname) + 1); } POST_SYSCALL(unlink)(long res, const void *pathname) {} PRE_SYSCALL(rename)(const void *oldname, const void *newname) { if (oldname) PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); if (newname) PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); } POST_SYSCALL(rename)(long res, const void *oldname, const void *newname) {} PRE_SYSCALL(chmod)(const void *filename, long mode) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(chmod)(long res, const void *filename, long mode) {} PRE_SYSCALL(fchmod)(long fd, long mode) {} POST_SYSCALL(fchmod)(long res, long fd, long mode) {} PRE_SYSCALL(fcntl)(long fd, long cmd, long arg) {} POST_SYSCALL(fcntl)(long res, long fd, long cmd, long arg) {} PRE_SYSCALL(fcntl64)(long fd, long cmd, long arg) {} POST_SYSCALL(fcntl64)(long res, long fd, long cmd, long arg) {} PRE_SYSCALL(pipe)(void *fildes) {} POST_SYSCALL(pipe)(long res, void *fildes) { if (res >= 0) { if (fildes) POST_WRITE(fildes, sizeof(int)); } } PRE_SYSCALL(pipe2)(void *fildes, long flags) {} POST_SYSCALL(pipe2)(long res, void *fildes, long flags) { if (res >= 0) { if (fildes) POST_WRITE(fildes, sizeof(int)); } } PRE_SYSCALL(dup)(long fildes) {} POST_SYSCALL(dup)(long res, long fildes) {} PRE_SYSCALL(dup2)(long oldfd, long newfd) {} POST_SYSCALL(dup2)(long res, long oldfd, long newfd) {} PRE_SYSCALL(dup3)(long oldfd, long newfd, long flags) {} POST_SYSCALL(dup3)(long res, long oldfd, long newfd, long flags) {} PRE_SYSCALL(ioperm)(long from, long num, long on) {} POST_SYSCALL(ioperm)(long res, long from, long num, long on) {} PRE_SYSCALL(ioctl)(long fd, long cmd, long arg) {} POST_SYSCALL(ioctl)(long res, long fd, long cmd, long arg) {} PRE_SYSCALL(flock)(long fd, long cmd) {} POST_SYSCALL(flock)(long res, long fd, long cmd) {} PRE_SYSCALL(io_setup)(long nr_reqs, void **ctx) { if (ctx) PRE_WRITE(ctx, sizeof(*ctx)); } POST_SYSCALL(io_setup)(long res, long nr_reqs, void **ctx) { if (res >= 0) { if (ctx) POST_WRITE(ctx, sizeof(*ctx)); // (*ctx) is actually a pointer to a kernel mapped page, and there are // people out there who are crazy enough to peek into that page's 32-byte // header. if (*ctx) POST_WRITE(*ctx, 32); } } PRE_SYSCALL(io_destroy)(long ctx) {} POST_SYSCALL(io_destroy)(long res, long ctx) {} PRE_SYSCALL(io_getevents)(long ctx_id, long min_nr, long nr, __sanitizer_io_event *ioevpp, void *timeout) { if (timeout) PRE_READ(timeout, struct_timespec_sz); } POST_SYSCALL(io_getevents)(long res, long ctx_id, long min_nr, long nr, __sanitizer_io_event *ioevpp, void *timeout) { if (res >= 0) { if (ioevpp) POST_WRITE(ioevpp, res * sizeof(*ioevpp)); if (timeout) POST_WRITE(timeout, struct_timespec_sz); } for (long i = 0; i < res; i++) { // We synchronize io_submit -> io_getevents/io_cancel using the // user-provided data context. Data is not necessary a pointer, it can be // an int, 0 or whatever; acquire/release will correctly handle this. // This scheme can lead to false negatives, e.g. when all operations // synchronize on 0. But there does not seem to be a better solution // (except wrapping all operations in own context, which is unreliable). // We can not reliably extract fildes in io_getevents. COMMON_SYSCALL_ACQUIRE((void*)ioevpp[i].data); } } PRE_SYSCALL(io_submit)(long ctx_id, long nr, __sanitizer_iocb **iocbpp) { for (long i = 0; i < nr; ++i) { uptr op = iocbpp[i]->aio_lio_opcode; void *data = (void*)iocbpp[i]->aio_data; void *buf = (void*)iocbpp[i]->aio_buf; uptr len = (uptr)iocbpp[i]->aio_nbytes; if (op == iocb_cmd_pwrite && buf && len) { PRE_READ(buf, len); } else if (op == iocb_cmd_pread && buf && len) { POST_WRITE(buf, len); } else if (op == iocb_cmd_pwritev) { __sanitizer_iovec *iovec = (__sanitizer_iovec*)buf; for (uptr v = 0; v < len; v++) PRE_READ(iovec[v].iov_base, iovec[v].iov_len); } else if (op == iocb_cmd_preadv) { __sanitizer_iovec *iovec = (__sanitizer_iovec*)buf; for (uptr v = 0; v < len; v++) POST_WRITE(iovec[v].iov_base, iovec[v].iov_len); } // See comment in io_getevents. COMMON_SYSCALL_RELEASE(data); } } POST_SYSCALL(io_submit)(long res, long ctx_id, long nr, __sanitizer_iocb **iocbpp) {} PRE_SYSCALL(io_cancel)(long ctx_id, __sanitizer_iocb *iocb, __sanitizer_io_event *result) { } POST_SYSCALL(io_cancel)(long res, long ctx_id, __sanitizer_iocb *iocb, __sanitizer_io_event *result) { if (res == 0) { if (result) { // See comment in io_getevents. COMMON_SYSCALL_ACQUIRE((void*)result->data); POST_WRITE(result, sizeof(*result)); } if (iocb) POST_WRITE(iocb, sizeof(*iocb)); } } PRE_SYSCALL(sendfile)(long out_fd, long in_fd, void *offset, long count) {} POST_SYSCALL(sendfile)(long res, long out_fd, long in_fd, __sanitizer___kernel_off_t *offset, long count) { if (res >= 0) { if (offset) POST_WRITE(offset, sizeof(*offset)); } } PRE_SYSCALL(sendfile64)(long out_fd, long in_fd, void *offset, long count) {} POST_SYSCALL(sendfile64)(long res, long out_fd, long in_fd, __sanitizer___kernel_loff_t *offset, long count) { if (res >= 0) { if (offset) POST_WRITE(offset, sizeof(*offset)); } } PRE_SYSCALL(readlink)(const void *path, void *buf, long bufsiz) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); } POST_SYSCALL(readlink)(long res, const void *path, void *buf, long bufsiz) { if (res >= 0) { if (buf) POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); } } PRE_SYSCALL(creat)(const void *pathname, long mode) { if (pathname) PRE_READ(pathname, __sanitizer::internal_strlen((const char *)pathname) + 1); } POST_SYSCALL(creat)(long res, const void *pathname, long mode) {} PRE_SYSCALL(open)(const void *filename, long flags, long mode) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(open)(long res, const void *filename, long flags, long mode) {} PRE_SYSCALL(close)(long fd) { COMMON_SYSCALL_FD_CLOSE((int)fd); } POST_SYSCALL(close)(long res, long fd) {} PRE_SYSCALL(access)(const void *filename, long mode) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(access)(long res, const void *filename, long mode) {} PRE_SYSCALL(vhangup)() {} POST_SYSCALL(vhangup)(long res) {} PRE_SYSCALL(chown)(const void *filename, long user, long group) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(chown)(long res, const void *filename, long user, long group) {} PRE_SYSCALL(lchown)(const void *filename, long user, long group) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(lchown)(long res, const void *filename, long user, long group) {} PRE_SYSCALL(fchown)(long fd, long user, long group) {} POST_SYSCALL(fchown)(long res, long fd, long user, long group) {} PRE_SYSCALL(chown16)(const void *filename, long user, long group) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(chown16)(long res, const void *filename, long user, long group) {} PRE_SYSCALL(lchown16)(const void *filename, long user, long group) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(lchown16)(long res, const void *filename, long user, long group) {} PRE_SYSCALL(fchown16)(long fd, long user, long group) {} POST_SYSCALL(fchown16)(long res, long fd, long user, long group) {} PRE_SYSCALL(setregid16)(long rgid, long egid) {} POST_SYSCALL(setregid16)(long res, long rgid, long egid) {} PRE_SYSCALL(setgid16)(long gid) {} POST_SYSCALL(setgid16)(long res, long gid) {} PRE_SYSCALL(setreuid16)(long ruid, long euid) {} POST_SYSCALL(setreuid16)(long res, long ruid, long euid) {} PRE_SYSCALL(setuid16)(long uid) {} POST_SYSCALL(setuid16)(long res, long uid) {} PRE_SYSCALL(setresuid16)(long ruid, long euid, long suid) {} POST_SYSCALL(setresuid16)(long res, long ruid, long euid, long suid) {} PRE_SYSCALL(getresuid16)(void *ruid, void *euid, void *suid) {} POST_SYSCALL(getresuid16)(long res, __sanitizer___kernel_old_uid_t *ruid, __sanitizer___kernel_old_uid_t *euid, __sanitizer___kernel_old_uid_t *suid) { if (res >= 0) { if (ruid) POST_WRITE(ruid, sizeof(*ruid)); if (euid) POST_WRITE(euid, sizeof(*euid)); if (suid) POST_WRITE(suid, sizeof(*suid)); } } PRE_SYSCALL(setresgid16)(long rgid, long egid, long sgid) {} POST_SYSCALL(setresgid16)(long res, long rgid, long egid, long sgid) {} PRE_SYSCALL(getresgid16)(void *rgid, void *egid, void *sgid) {} POST_SYSCALL(getresgid16)(long res, __sanitizer___kernel_old_gid_t *rgid, __sanitizer___kernel_old_gid_t *egid, __sanitizer___kernel_old_gid_t *sgid) { if (res >= 0) { if (rgid) POST_WRITE(rgid, sizeof(*rgid)); if (egid) POST_WRITE(egid, sizeof(*egid)); if (sgid) POST_WRITE(sgid, sizeof(*sgid)); } } PRE_SYSCALL(setfsuid16)(long uid) {} POST_SYSCALL(setfsuid16)(long res, long uid) {} PRE_SYSCALL(setfsgid16)(long gid) {} POST_SYSCALL(setfsgid16)(long res, long gid) {} PRE_SYSCALL(getgroups16)(long gidsetsize, __sanitizer___kernel_old_gid_t *grouplist) {} POST_SYSCALL(getgroups16)(long res, long gidsetsize, __sanitizer___kernel_old_gid_t *grouplist) { if (res >= 0) { if (grouplist) POST_WRITE(grouplist, res * sizeof(*grouplist)); } } PRE_SYSCALL(setgroups16)(long gidsetsize, __sanitizer___kernel_old_gid_t *grouplist) { if (grouplist) POST_WRITE(grouplist, gidsetsize * sizeof(*grouplist)); } POST_SYSCALL(setgroups16)(long res, long gidsetsize, __sanitizer___kernel_old_gid_t *grouplist) {} PRE_SYSCALL(getuid16)() {} POST_SYSCALL(getuid16)(long res) {} PRE_SYSCALL(geteuid16)() {} POST_SYSCALL(geteuid16)(long res) {} PRE_SYSCALL(getgid16)() {} POST_SYSCALL(getgid16)(long res) {} PRE_SYSCALL(getegid16)() {} POST_SYSCALL(getegid16)(long res) {} PRE_SYSCALL(utime)(void *filename, void *times) {} POST_SYSCALL(utime)(long res, void *filename, void *times) { if (res >= 0) { if (filename) POST_WRITE(filename, __sanitizer::internal_strlen((const char *)filename) + 1); if (times) POST_WRITE(times, struct_utimbuf_sz); } } PRE_SYSCALL(utimes)(void *filename, void *utimes) {} POST_SYSCALL(utimes)(long res, void *filename, void *utimes) { if (res >= 0) { if (filename) POST_WRITE(filename, __sanitizer::internal_strlen((const char *)filename) + 1); if (utimes) POST_WRITE(utimes, timeval_sz); } } PRE_SYSCALL(lseek)(long fd, long offset, long origin) {} POST_SYSCALL(lseek)(long res, long fd, long offset, long origin) {} PRE_SYSCALL(llseek)(long fd, long offset_high, long offset_low, void *result, long origin) {} POST_SYSCALL(llseek)(long res, long fd, long offset_high, long offset_low, void *result, long origin) { if (res >= 0) { if (result) POST_WRITE(result, sizeof(long long)); } } PRE_SYSCALL(readv)(long fd, const __sanitizer_iovec *vec, long vlen) {} POST_SYSCALL(readv)(long res, long fd, const __sanitizer_iovec *vec, long vlen) { if (res >= 0) { if (vec) kernel_write_iovec(vec, vlen, res); } } PRE_SYSCALL(write)(long fd, const void *buf, long count) { if (buf) PRE_READ(buf, count); } POST_SYSCALL(write)(long res, long fd, const void *buf, long count) {} PRE_SYSCALL(writev)(long fd, const __sanitizer_iovec *vec, long vlen) {} POST_SYSCALL(writev)(long res, long fd, const __sanitizer_iovec *vec, long vlen) { if (res >= 0) { if (vec) kernel_read_iovec(vec, vlen, res); } } #ifdef _LP64 PRE_SYSCALL(pread64)(long fd, void *buf, long count, long pos) {} POST_SYSCALL(pread64)(long res, long fd, void *buf, long count, long pos) { if (res >= 0) { if (buf) POST_WRITE(buf, res); } } PRE_SYSCALL(pwrite64)(long fd, const void *buf, long count, long pos) { if (buf) PRE_READ(buf, count); } POST_SYSCALL(pwrite64)(long res, long fd, const void *buf, long count, long pos) {} #else PRE_SYSCALL(pread64)(long fd, void *buf, long count, long pos0, long pos1) {} POST_SYSCALL(pread64)(long res, long fd, void *buf, long count, long pos0, long pos1) { if (res >= 0) { if (buf) POST_WRITE(buf, res); } } PRE_SYSCALL(pwrite64)(long fd, const void *buf, long count, long pos0, long pos1) { if (buf) PRE_READ(buf, count); } POST_SYSCALL(pwrite64)(long res, long fd, const void *buf, long count, long pos0, long pos1) {} #endif PRE_SYSCALL(preadv)(long fd, const __sanitizer_iovec *vec, long vlen, long pos_l, long pos_h) {} POST_SYSCALL(preadv)(long res, long fd, const __sanitizer_iovec *vec, long vlen, long pos_l, long pos_h) { if (res >= 0) { if (vec) kernel_write_iovec(vec, vlen, res); } } PRE_SYSCALL(pwritev)(long fd, const __sanitizer_iovec *vec, long vlen, long pos_l, long pos_h) {} POST_SYSCALL(pwritev)(long res, long fd, const __sanitizer_iovec *vec, long vlen, long pos_l, long pos_h) { if (res >= 0) { if (vec) kernel_read_iovec(vec, vlen, res); } } PRE_SYSCALL(getcwd)(void *buf, long size) {} POST_SYSCALL(getcwd)(long res, void *buf, long size) { if (res >= 0) { if (buf) POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); } } PRE_SYSCALL(mkdir)(const void *pathname, long mode) { if (pathname) PRE_READ(pathname, __sanitizer::internal_strlen((const char *)pathname) + 1); } POST_SYSCALL(mkdir)(long res, const void *pathname, long mode) {} PRE_SYSCALL(chdir)(const void *filename) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(chdir)(long res, const void *filename) {} PRE_SYSCALL(fchdir)(long fd) {} POST_SYSCALL(fchdir)(long res, long fd) {} PRE_SYSCALL(rmdir)(const void *pathname) { if (pathname) PRE_READ(pathname, __sanitizer::internal_strlen((const char *)pathname) + 1); } POST_SYSCALL(rmdir)(long res, const void *pathname) {} PRE_SYSCALL(lookup_dcookie)(u64 cookie64, void *buf, long len) {} POST_SYSCALL(lookup_dcookie)(long res, u64 cookie64, void *buf, long len) { if (res >= 0) { if (buf) POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); } } PRE_SYSCALL(quotactl)(long cmd, const void *special, long id, void *addr) { if (special) PRE_READ(special, __sanitizer::internal_strlen((const char *)special) + 1); } POST_SYSCALL(quotactl)(long res, long cmd, const void *special, long id, void *addr) {} PRE_SYSCALL(getdents)(long fd, void *dirent, long count) {} POST_SYSCALL(getdents)(long res, long fd, void *dirent, long count) { if (res >= 0) { if (dirent) POST_WRITE(dirent, res); } } PRE_SYSCALL(getdents64)(long fd, void *dirent, long count) {} POST_SYSCALL(getdents64)(long res, long fd, void *dirent, long count) { if (res >= 0) { if (dirent) POST_WRITE(dirent, res); } } PRE_SYSCALL(setsockopt)(long fd, long level, long optname, void *optval, long optlen) {} POST_SYSCALL(setsockopt)(long res, long fd, long level, long optname, void *optval, long optlen) { if (res >= 0) { if (optval) POST_WRITE(optval, __sanitizer::internal_strlen((const char *)optval) + 1); } } PRE_SYSCALL(getsockopt)(long fd, long level, long optname, void *optval, void *optlen) {} POST_SYSCALL(getsockopt)(long res, long fd, long level, long optname, void *optval, void *optlen) { if (res >= 0) { if (optval) POST_WRITE(optval, __sanitizer::internal_strlen((const char *)optval) + 1); if (optlen) POST_WRITE(optlen, sizeof(int)); } } PRE_SYSCALL(bind)(long arg0, sanitizer_kernel_sockaddr *arg1, long arg2) {} POST_SYSCALL(bind)(long res, long arg0, sanitizer_kernel_sockaddr *arg1, long arg2) { if (res >= 0) { if (arg1) POST_WRITE(arg1, sizeof(*arg1)); } } PRE_SYSCALL(connect)(long arg0, sanitizer_kernel_sockaddr *arg1, long arg2) {} POST_SYSCALL(connect)(long res, long arg0, sanitizer_kernel_sockaddr *arg1, long arg2) { if (res >= 0) { if (arg1) POST_WRITE(arg1, sizeof(*arg1)); } } PRE_SYSCALL(accept)(long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) {} POST_SYSCALL(accept)(long res, long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) { if (res >= 0) { if (arg1) POST_WRITE(arg1, sizeof(*arg1)); if (arg2) POST_WRITE(arg2, sizeof(unsigned)); } } PRE_SYSCALL(accept4)(long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2, long arg3) {} POST_SYSCALL(accept4)(long res, long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2, long arg3) { if (res >= 0) { if (arg1) POST_WRITE(arg1, sizeof(*arg1)); if (arg2) POST_WRITE(arg2, sizeof(unsigned)); } } PRE_SYSCALL(getsockname)(long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) {} POST_SYSCALL(getsockname)(long res, long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) { if (res >= 0) { if (arg1) POST_WRITE(arg1, sizeof(*arg1)); if (arg2) POST_WRITE(arg2, sizeof(unsigned)); } } PRE_SYSCALL(getpeername)(long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) {} POST_SYSCALL(getpeername)(long res, long arg0, sanitizer_kernel_sockaddr *arg1, void *arg2) { if (res >= 0) { if (arg1) POST_WRITE(arg1, sizeof(*arg1)); if (arg2) POST_WRITE(arg2, sizeof(unsigned)); } } PRE_SYSCALL(send)(long arg0, void *arg1, long arg2, long arg3) {} POST_SYSCALL(send)(long res, long arg0, void *arg1, long arg2, long arg3) { if (res) { if (arg1) POST_READ(arg1, res); } } PRE_SYSCALL(sendto)(long arg0, void *arg1, long arg2, long arg3, sanitizer_kernel_sockaddr *arg4, long arg5) {} POST_SYSCALL(sendto)(long res, long arg0, void *arg1, long arg2, long arg3, sanitizer_kernel_sockaddr *arg4, long arg5) { if (res >= 0) { if (arg1) POST_READ(arg1, res); if (arg4) POST_WRITE(arg4, sizeof(*arg4)); } } PRE_SYSCALL(sendmsg)(long fd, void *msg, long flags) {} POST_SYSCALL(sendmsg)(long res, long fd, void *msg, long flags) { // FIXME: POST_READ } PRE_SYSCALL(sendmmsg)(long fd, void *msg, long vlen, long flags) {} POST_SYSCALL(sendmmsg)(long res, long fd, void *msg, long vlen, long flags) { // FIXME: POST_READ } PRE_SYSCALL(recv)(long arg0, void *buf, long len, long flags) {} POST_SYSCALL(recv)(long res, void *buf, long len, long flags) { if (res >= 0) { if (buf) POST_WRITE(buf, res); } } PRE_SYSCALL(recvfrom)(long arg0, void *buf, long len, long flags, sanitizer_kernel_sockaddr *arg4, void *arg5) {} POST_SYSCALL(recvfrom)(long res, long arg0, void *buf, long len, long flags, sanitizer_kernel_sockaddr *arg4, void *arg5) { if (res >= 0) { if (buf) POST_WRITE(buf, res); if (arg4) POST_WRITE(arg4, sizeof(*arg4)); if (arg5) POST_WRITE(arg5, sizeof(int)); } } PRE_SYSCALL(socket)(long arg0, long arg1, long arg2) {} POST_SYSCALL(socket)(long res, long arg0, long arg1, long arg2) {} PRE_SYSCALL(socketpair)(long arg0, long arg1, long arg2, void *arg3) {} POST_SYSCALL(socketpair)(long res, long arg0, long arg1, long arg2, void *arg3) { if (res >= 0) { if (arg3) POST_WRITE(arg3, sizeof(int)); } } PRE_SYSCALL(socketcall)(long call, void *args) {} POST_SYSCALL(socketcall)(long res, long call, void *args) { if (res >= 0) { if (args) POST_WRITE(args, sizeof(long)); } } PRE_SYSCALL(listen)(long arg0, long arg1) {} POST_SYSCALL(listen)(long res, long arg0, long arg1) {} PRE_SYSCALL(poll)(void *ufds, long nfds, long timeout) {} POST_SYSCALL(poll)(long res, __sanitizer_pollfd *ufds, long nfds, long timeout) { if (res >= 0) { if (ufds) POST_WRITE(ufds, nfds * sizeof(*ufds)); } } PRE_SYSCALL(select)(long n, __sanitizer___kernel_fd_set *inp, __sanitizer___kernel_fd_set *outp, __sanitizer___kernel_fd_set *exp, void *tvp) {} POST_SYSCALL(select)(long res, long n, __sanitizer___kernel_fd_set *inp, __sanitizer___kernel_fd_set *outp, __sanitizer___kernel_fd_set *exp, void *tvp) { if (res >= 0) { if (inp) POST_WRITE(inp, sizeof(*inp)); if (outp) POST_WRITE(outp, sizeof(*outp)); if (exp) POST_WRITE(exp, sizeof(*exp)); if (tvp) POST_WRITE(tvp, timeval_sz); } } PRE_SYSCALL(old_select)(void *arg) {} POST_SYSCALL(old_select)(long res, void *arg) {} PRE_SYSCALL(epoll_create)(long size) {} POST_SYSCALL(epoll_create)(long res, long size) {} PRE_SYSCALL(epoll_create1)(long flags) {} POST_SYSCALL(epoll_create1)(long res, long flags) {} PRE_SYSCALL(epoll_ctl)(long epfd, long op, long fd, void *event) {} POST_SYSCALL(epoll_ctl)(long res, long epfd, long op, long fd, void *event) { if (res >= 0) { if (event) POST_WRITE(event, struct_epoll_event_sz); } } PRE_SYSCALL(epoll_wait)(long epfd, void *events, long maxevents, long timeout) { } POST_SYSCALL(epoll_wait)(long res, long epfd, void *events, long maxevents, long timeout) { if (res >= 0) { if (events) POST_WRITE(events, struct_epoll_event_sz); } } PRE_SYSCALL(epoll_pwait)(long epfd, void *events, long maxevents, long timeout, const kernel_sigset_t *sigmask, long sigsetsize) { if (sigmask) PRE_READ(sigmask, sigsetsize); } POST_SYSCALL(epoll_pwait)(long res, long epfd, void *events, long maxevents, long timeout, const void *sigmask, long sigsetsize) { if (res >= 0) { if (events) POST_WRITE(events, struct_epoll_event_sz); } } PRE_SYSCALL(gethostname)(void *name, long len) {} POST_SYSCALL(gethostname)(long res, void *name, long len) { if (res >= 0) { if (name) POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); } } PRE_SYSCALL(sethostname)(void *name, long len) {} POST_SYSCALL(sethostname)(long res, void *name, long len) { if (res >= 0) { if (name) POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); } } PRE_SYSCALL(setdomainname)(void *name, long len) {} POST_SYSCALL(setdomainname)(long res, void *name, long len) { if (res >= 0) { if (name) POST_WRITE(name, __sanitizer::internal_strlen((const char *)name) + 1); } } PRE_SYSCALL(newuname)(void *name) {} POST_SYSCALL(newuname)(long res, void *name) { if (res >= 0) { if (name) POST_WRITE(name, struct_new_utsname_sz); } } PRE_SYSCALL(uname)(void *arg0) {} POST_SYSCALL(uname)(long res, void *arg0) { if (res >= 0) { if (arg0) POST_WRITE(arg0, struct_old_utsname_sz); } } PRE_SYSCALL(olduname)(void *arg0) {} POST_SYSCALL(olduname)(long res, void *arg0) { if (res >= 0) { if (arg0) POST_WRITE(arg0, struct_oldold_utsname_sz); } } PRE_SYSCALL(getrlimit)(long resource, void *rlim) {} POST_SYSCALL(getrlimit)(long res, long resource, void *rlim) { if (res >= 0) { if (rlim) POST_WRITE(rlim, struct_rlimit_sz); } } PRE_SYSCALL(old_getrlimit)(long resource, void *rlim) {} POST_SYSCALL(old_getrlimit)(long res, long resource, void *rlim) { if (res >= 0) { if (rlim) POST_WRITE(rlim, struct_rlimit_sz); } } PRE_SYSCALL(setrlimit)(long resource, void *rlim) {} POST_SYSCALL(setrlimit)(long res, long resource, void *rlim) { if (res >= 0) { if (rlim) POST_WRITE(rlim, struct_rlimit_sz); } } #if !SANITIZER_ANDROID PRE_SYSCALL(prlimit64)(long pid, long resource, const void *new_rlim, void *old_rlim) { if (new_rlim) PRE_READ(new_rlim, struct_rlimit64_sz); } POST_SYSCALL(prlimit64)(long res, long pid, long resource, const void *new_rlim, void *old_rlim) { if (res >= 0) { if (old_rlim) POST_WRITE(old_rlim, struct_rlimit64_sz); } } #endif PRE_SYSCALL(getrusage)(long who, void *ru) {} POST_SYSCALL(getrusage)(long res, long who, void *ru) { if (res >= 0) { if (ru) POST_WRITE(ru, struct_rusage_sz); } } PRE_SYSCALL(umask)(long mask) {} POST_SYSCALL(umask)(long res, long mask) {} PRE_SYSCALL(msgget)(long key, long msgflg) {} POST_SYSCALL(msgget)(long res, long key, long msgflg) {} PRE_SYSCALL(msgsnd)(long msqid, void *msgp, long msgsz, long msgflg) { if (msgp) PRE_READ(msgp, msgsz); } POST_SYSCALL(msgsnd)(long res, long msqid, void *msgp, long msgsz, long msgflg) {} PRE_SYSCALL(msgrcv)(long msqid, void *msgp, long msgsz, long msgtyp, long msgflg) {} POST_SYSCALL(msgrcv)(long res, long msqid, void *msgp, long msgsz, long msgtyp, long msgflg) { if (res >= 0) { if (msgp) POST_WRITE(msgp, res); } } #if !SANITIZER_ANDROID PRE_SYSCALL(msgctl)(long msqid, long cmd, void *buf) {} POST_SYSCALL(msgctl)(long res, long msqid, long cmd, void *buf) { if (res >= 0) { if (buf) POST_WRITE(buf, struct_msqid_ds_sz); } } #endif PRE_SYSCALL(semget)(long key, long nsems, long semflg) {} POST_SYSCALL(semget)(long res, long key, long nsems, long semflg) {} PRE_SYSCALL(semop)(long semid, void *sops, long nsops) {} POST_SYSCALL(semop)(long res, long semid, void *sops, long nsops) {} PRE_SYSCALL(semctl)(long semid, long semnum, long cmd, void *arg) {} POST_SYSCALL(semctl)(long res, long semid, long semnum, long cmd, void *arg) {} PRE_SYSCALL(semtimedop)(long semid, void *sops, long nsops, const void *timeout) { if (timeout) PRE_READ(timeout, struct_timespec_sz); } POST_SYSCALL(semtimedop)(long res, long semid, void *sops, long nsops, const void *timeout) {} PRE_SYSCALL(shmat)(long shmid, void *shmaddr, long shmflg) {} POST_SYSCALL(shmat)(long res, long shmid, void *shmaddr, long shmflg) { if (res >= 0) { if (shmaddr) POST_WRITE(shmaddr, __sanitizer::internal_strlen((const char *)shmaddr) + 1); } } PRE_SYSCALL(shmget)(long key, long size, long flag) {} POST_SYSCALL(shmget)(long res, long key, long size, long flag) {} PRE_SYSCALL(shmdt)(void *shmaddr) {} POST_SYSCALL(shmdt)(long res, void *shmaddr) { if (res >= 0) { if (shmaddr) POST_WRITE(shmaddr, __sanitizer::internal_strlen((const char *)shmaddr) + 1); } } PRE_SYSCALL(ipc)(long call, long first, long second, long third, void *ptr, long fifth) {} POST_SYSCALL(ipc)(long res, long call, long first, long second, long third, void *ptr, long fifth) {} #if !SANITIZER_ANDROID PRE_SYSCALL(shmctl)(long shmid, long cmd, void *buf) {} POST_SYSCALL(shmctl)(long res, long shmid, long cmd, void *buf) { if (res >= 0) { if (buf) POST_WRITE(buf, sizeof(__sanitizer_shmid_ds)); } } PRE_SYSCALL(mq_open)(const void *name, long oflag, long mode, void *attr) { if (name) PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); } POST_SYSCALL(mq_open)(long res, const void *name, long oflag, long mode, void *attr) { if (res >= 0) { if (attr) POST_WRITE(attr, struct_mq_attr_sz); } } PRE_SYSCALL(mq_unlink)(const void *name) { if (name) PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); } POST_SYSCALL(mq_unlink)(long res, const void *name) {} PRE_SYSCALL(mq_timedsend)(long mqdes, const void *msg_ptr, long msg_len, long msg_prio, const void *abs_timeout) { if (msg_ptr) PRE_READ(msg_ptr, msg_len); if (abs_timeout) PRE_READ(abs_timeout, struct_timespec_sz); } POST_SYSCALL(mq_timedsend)(long res, long mqdes, const void *msg_ptr, long msg_len, long msg_prio, const void *abs_timeout) {} PRE_SYSCALL(mq_timedreceive)(long mqdes, void *msg_ptr, long msg_len, void *msg_prio, const void *abs_timeout) { if (abs_timeout) PRE_READ(abs_timeout, struct_timespec_sz); } POST_SYSCALL(mq_timedreceive)(long res, long mqdes, void *msg_ptr, long msg_len, int *msg_prio, const void *abs_timeout) { if (res >= 0) { if (msg_ptr) POST_WRITE(msg_ptr, res); if (msg_prio) POST_WRITE(msg_prio, sizeof(*msg_prio)); } } PRE_SYSCALL(mq_notify)(long mqdes, const void *notification) { if (notification) PRE_READ(notification, struct_sigevent_sz); } POST_SYSCALL(mq_notify)(long res, long mqdes, const void *notification) {} PRE_SYSCALL(mq_getsetattr)(long mqdes, const void *mqstat, void *omqstat) { if (mqstat) PRE_READ(mqstat, struct_mq_attr_sz); } POST_SYSCALL(mq_getsetattr)(long res, long mqdes, const void *mqstat, void *omqstat) { if (res >= 0) { if (omqstat) POST_WRITE(omqstat, struct_mq_attr_sz); } } #endif // SANITIZER_ANDROID PRE_SYSCALL(pciconfig_iobase)(long which, long bus, long devfn) {} POST_SYSCALL(pciconfig_iobase)(long res, long which, long bus, long devfn) {} PRE_SYSCALL(pciconfig_read)(long bus, long dfn, long off, long len, void *buf) { } POST_SYSCALL(pciconfig_read)(long res, long bus, long dfn, long off, long len, void *buf) {} PRE_SYSCALL(pciconfig_write)(long bus, long dfn, long off, long len, void *buf) {} POST_SYSCALL(pciconfig_write)(long res, long bus, long dfn, long off, long len, void *buf) {} PRE_SYSCALL(swapon)(const void *specialfile, long swap_flags) { if (specialfile) PRE_READ(specialfile, __sanitizer::internal_strlen((const char *)specialfile) + 1); } POST_SYSCALL(swapon)(long res, const void *specialfile, long swap_flags) {} PRE_SYSCALL(swapoff)(const void *specialfile) { if (specialfile) PRE_READ(specialfile, __sanitizer::internal_strlen((const char *)specialfile) + 1); } POST_SYSCALL(swapoff)(long res, const void *specialfile) {} PRE_SYSCALL(sysctl)(__sanitizer___sysctl_args *args) { if (args) { if (args->name) PRE_READ(args->name, args->nlen * sizeof(*args->name)); if (args->newval) PRE_READ(args->name, args->newlen); } } POST_SYSCALL(sysctl)(long res, __sanitizer___sysctl_args *args) { if (res >= 0) { if (args && args->oldval && args->oldlenp) { POST_WRITE(args->oldlenp, sizeof(*args->oldlenp)); POST_WRITE(args->oldval, *args->oldlenp); } } } PRE_SYSCALL(sysinfo)(void *info) {} POST_SYSCALL(sysinfo)(long res, void *info) { if (res >= 0) { if (info) POST_WRITE(info, struct_sysinfo_sz); } } PRE_SYSCALL(sysfs)(long option, long arg1, long arg2) {} POST_SYSCALL(sysfs)(long res, long option, long arg1, long arg2) {} PRE_SYSCALL(syslog)(long type, void *buf, long len) {} POST_SYSCALL(syslog)(long res, long type, void *buf, long len) { if (res >= 0) { if (buf) POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); } } PRE_SYSCALL(uselib)(const void *library) { if (library) PRE_READ(library, __sanitizer::internal_strlen((const char *)library) + 1); } POST_SYSCALL(uselib)(long res, const void *library) {} PRE_SYSCALL(ni_syscall)() {} POST_SYSCALL(ni_syscall)(long res) {} PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) { -#if !SANITIZER_ANDROID && (defined(__i386) || defined (__x86_64)) +#if !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64)) if (data) { if (request == ptrace_setregs) { PRE_READ((void *)data, struct_user_regs_struct_sz); } else if (request == ptrace_setfpregs) { PRE_READ((void *)data, struct_user_fpregs_struct_sz); } else if (request == ptrace_setfpxregs) { PRE_READ((void *)data, struct_user_fpxregs_struct_sz); } else if (request == ptrace_setsiginfo) { PRE_READ((void *)data, siginfo_t_sz); } else if (request == ptrace_setregset) { __sanitizer_iovec *iov = (__sanitizer_iovec *)data; PRE_READ(iov->iov_base, iov->iov_len); } } #endif } POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) { -#if !SANITIZER_ANDROID && (defined(__i386) || defined (__x86_64)) +#if !SANITIZER_ANDROID && \ + (defined(__i386) || defined(__x86_64) || defined(__mips64)) if (res >= 0 && data) { // Note that this is different from the interceptor in // sanitizer_common_interceptors.inc. // PEEK* requests return resulting values through data pointer. if (request == ptrace_getregs) { POST_WRITE((void *)data, struct_user_regs_struct_sz); } else if (request == ptrace_getfpregs) { POST_WRITE((void *)data, struct_user_fpregs_struct_sz); } else if (request == ptrace_getfpxregs) { POST_WRITE((void *)data, struct_user_fpxregs_struct_sz); } else if (request == ptrace_getsiginfo) { POST_WRITE((void *)data, siginfo_t_sz); } else if (request == ptrace_getregset) { __sanitizer_iovec *iov = (__sanitizer_iovec *)data; POST_WRITE(iov->iov_base, iov->iov_len); } else if (request == ptrace_peekdata || request == ptrace_peektext || request == ptrace_peekuser) { POST_WRITE((void *)data, sizeof(void *)); } } #endif } PRE_SYSCALL(add_key)(const void *_type, const void *_description, const void *_payload, long plen, long destringid) { if (_type) PRE_READ(_type, __sanitizer::internal_strlen((const char *)_type) + 1); if (_description) PRE_READ(_description, __sanitizer::internal_strlen((const char *)_description) + 1); } POST_SYSCALL(add_key)(long res, const void *_type, const void *_description, const void *_payload, long plen, long destringid) {} PRE_SYSCALL(request_key)(const void *_type, const void *_description, const void *_callout_info, long destringid) { if (_type) PRE_READ(_type, __sanitizer::internal_strlen((const char *)_type) + 1); if (_description) PRE_READ(_description, __sanitizer::internal_strlen((const char *)_description) + 1); if (_callout_info) PRE_READ(_callout_info, __sanitizer::internal_strlen((const char *)_callout_info) + 1); } POST_SYSCALL(request_key)(long res, const void *_type, const void *_description, const void *_callout_info, long destringid) {} PRE_SYSCALL(keyctl)(long cmd, long arg2, long arg3, long arg4, long arg5) {} POST_SYSCALL(keyctl)(long res, long cmd, long arg2, long arg3, long arg4, long arg5) {} PRE_SYSCALL(ioprio_set)(long which, long who, long ioprio) {} POST_SYSCALL(ioprio_set)(long res, long which, long who, long ioprio) {} PRE_SYSCALL(ioprio_get)(long which, long who) {} POST_SYSCALL(ioprio_get)(long res, long which, long who) {} PRE_SYSCALL(set_mempolicy)(long mode, void *nmask, long maxnode) {} POST_SYSCALL(set_mempolicy)(long res, long mode, void *nmask, long maxnode) { if (res >= 0) { if (nmask) POST_WRITE(nmask, sizeof(long)); } } PRE_SYSCALL(migrate_pages)(long pid, long maxnode, const void *from, const void *to) { if (from) PRE_READ(from, sizeof(long)); if (to) PRE_READ(to, sizeof(long)); } POST_SYSCALL(migrate_pages)(long res, long pid, long maxnode, const void *from, const void *to) {} PRE_SYSCALL(move_pages)(long pid, long nr_pages, const void **pages, const int *nodes, int *status, long flags) { if (pages) PRE_READ(pages, nr_pages * sizeof(*pages)); if (nodes) PRE_READ(nodes, nr_pages * sizeof(*nodes)); } POST_SYSCALL(move_pages)(long res, long pid, long nr_pages, const void **pages, const int *nodes, int *status, long flags) { if (res >= 0) { if (status) POST_WRITE(status, nr_pages * sizeof(*status)); } } PRE_SYSCALL(mbind)(long start, long len, long mode, void *nmask, long maxnode, long flags) {} POST_SYSCALL(mbind)(long res, long start, long len, long mode, void *nmask, long maxnode, long flags) { if (res >= 0) { if (nmask) POST_WRITE(nmask, sizeof(long)); } } PRE_SYSCALL(get_mempolicy)(void *policy, void *nmask, long maxnode, long addr, long flags) {} POST_SYSCALL(get_mempolicy)(long res, void *policy, void *nmask, long maxnode, long addr, long flags) { if (res >= 0) { if (policy) POST_WRITE(policy, sizeof(int)); if (nmask) POST_WRITE(nmask, sizeof(long)); } } PRE_SYSCALL(inotify_init)() {} POST_SYSCALL(inotify_init)(long res) {} PRE_SYSCALL(inotify_init1)(long flags) {} POST_SYSCALL(inotify_init1)(long res, long flags) {} PRE_SYSCALL(inotify_add_watch)(long fd, const void *path, long mask) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); } POST_SYSCALL(inotify_add_watch)(long res, long fd, const void *path, long mask) {} PRE_SYSCALL(inotify_rm_watch)(long fd, long wd) {} POST_SYSCALL(inotify_rm_watch)(long res, long fd, long wd) {} PRE_SYSCALL(spu_run)(long fd, void *unpc, void *ustatus) {} POST_SYSCALL(spu_run)(long res, long fd, unsigned *unpc, unsigned *ustatus) { if (res >= 0) { if (unpc) POST_WRITE(unpc, sizeof(*unpc)); if (ustatus) POST_WRITE(ustatus, sizeof(*ustatus)); } } PRE_SYSCALL(spu_create)(const void *name, long flags, long mode, long fd) { if (name) PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1); } POST_SYSCALL(spu_create)(long res, const void *name, long flags, long mode, long fd) {} PRE_SYSCALL(mknodat)(long dfd, const void *filename, long mode, long dev) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(mknodat)(long res, long dfd, const void *filename, long mode, long dev) {} PRE_SYSCALL(mkdirat)(long dfd, const void *pathname, long mode) { if (pathname) PRE_READ(pathname, __sanitizer::internal_strlen((const char *)pathname) + 1); } POST_SYSCALL(mkdirat)(long res, long dfd, const void *pathname, long mode) {} PRE_SYSCALL(unlinkat)(long dfd, const void *pathname, long flag) { if (pathname) PRE_READ(pathname, __sanitizer::internal_strlen((const char *)pathname) + 1); } POST_SYSCALL(unlinkat)(long res, long dfd, const void *pathname, long flag) {} PRE_SYSCALL(symlinkat)(const void *oldname, long newdfd, const void *newname) { if (oldname) PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); if (newname) PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); } POST_SYSCALL(symlinkat)(long res, const void *oldname, long newdfd, const void *newname) {} PRE_SYSCALL(linkat)(long olddfd, const void *oldname, long newdfd, const void *newname, long flags) { if (oldname) PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); if (newname) PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); } POST_SYSCALL(linkat)(long res, long olddfd, const void *oldname, long newdfd, const void *newname, long flags) {} PRE_SYSCALL(renameat)(long olddfd, const void *oldname, long newdfd, const void *newname) { if (oldname) PRE_READ(oldname, __sanitizer::internal_strlen((const char *)oldname) + 1); if (newname) PRE_READ(newname, __sanitizer::internal_strlen((const char *)newname) + 1); } POST_SYSCALL(renameat)(long res, long olddfd, const void *oldname, long newdfd, const void *newname) {} PRE_SYSCALL(futimesat)(long dfd, const void *filename, void *utimes) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(futimesat)(long res, long dfd, const void *filename, void *utimes) { if (res >= 0) { if (utimes) POST_WRITE(utimes, timeval_sz); } } PRE_SYSCALL(faccessat)(long dfd, const void *filename, long mode) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(faccessat)(long res, long dfd, const void *filename, long mode) {} PRE_SYSCALL(fchmodat)(long dfd, const void *filename, long mode) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(fchmodat)(long res, long dfd, const void *filename, long mode) {} PRE_SYSCALL(fchownat)(long dfd, const void *filename, long user, long group, long flag) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(fchownat)(long res, long dfd, const void *filename, long user, long group, long flag) {} PRE_SYSCALL(openat)(long dfd, const void *filename, long flags, long mode) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(openat)(long res, long dfd, const void *filename, long flags, long mode) {} PRE_SYSCALL(newfstatat)(long dfd, const void *filename, void *statbuf, long flag) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(newfstatat)(long res, long dfd, const void *filename, void *statbuf, long flag) { if (res >= 0) { if (statbuf) POST_WRITE(statbuf, struct_kernel_stat_sz); } } PRE_SYSCALL(fstatat64)(long dfd, const void *filename, void *statbuf, long flag) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(fstatat64)(long res, long dfd, const void *filename, void *statbuf, long flag) { if (res >= 0) { if (statbuf) POST_WRITE(statbuf, struct_kernel_stat64_sz); } } PRE_SYSCALL(readlinkat)(long dfd, const void *path, void *buf, long bufsiz) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); } POST_SYSCALL(readlinkat)(long res, long dfd, const void *path, void *buf, long bufsiz) { if (res >= 0) { if (buf) POST_WRITE(buf, __sanitizer::internal_strlen((const char *)buf) + 1); } } PRE_SYSCALL(utimensat)(long dfd, const void *filename, void *utimes, long flags) { if (filename) PRE_READ(filename, __sanitizer::internal_strlen((const char *)filename) + 1); } POST_SYSCALL(utimensat)(long res, long dfd, const void *filename, void *utimes, long flags) { if (res >= 0) { if (utimes) POST_WRITE(utimes, struct_timespec_sz); } } PRE_SYSCALL(unshare)(long unshare_flags) {} POST_SYSCALL(unshare)(long res, long unshare_flags) {} PRE_SYSCALL(splice)(long fd_in, void *off_in, long fd_out, void *off_out, long len, long flags) {} POST_SYSCALL(splice)(long res, long fd_in, void *off_in, long fd_out, void *off_out, long len, long flags) { if (res >= 0) { if (off_in) POST_WRITE(off_in, sizeof(long long)); if (off_out) POST_WRITE(off_out, sizeof(long long)); } } PRE_SYSCALL(vmsplice)(long fd, const __sanitizer_iovec *iov, long nr_segs, long flags) {} POST_SYSCALL(vmsplice)(long res, long fd, const __sanitizer_iovec *iov, long nr_segs, long flags) { if (res >= 0) { if (iov) kernel_read_iovec(iov, nr_segs, res); } } PRE_SYSCALL(tee)(long fdin, long fdout, long len, long flags) {} POST_SYSCALL(tee)(long res, long fdin, long fdout, long len, long flags) {} PRE_SYSCALL(get_robust_list)(long pid, void *head_ptr, void *len_ptr) {} POST_SYSCALL(get_robust_list)(long res, long pid, void *head_ptr, void *len_ptr) {} PRE_SYSCALL(set_robust_list)(void *head, long len) {} POST_SYSCALL(set_robust_list)(long res, void *head, long len) {} PRE_SYSCALL(getcpu)(void *cpu, void *node, void *cache) {} POST_SYSCALL(getcpu)(long res, void *cpu, void *node, void *cache) { if (res >= 0) { if (cpu) POST_WRITE(cpu, sizeof(unsigned)); if (node) POST_WRITE(node, sizeof(unsigned)); // The third argument to this system call is nowadays unused. } } PRE_SYSCALL(signalfd)(long ufd, void *user_mask, long sizemask) {} POST_SYSCALL(signalfd)(long res, long ufd, kernel_sigset_t *user_mask, long sizemask) { if (res >= 0) { if (user_mask) POST_WRITE(user_mask, sizemask); } } PRE_SYSCALL(signalfd4)(long ufd, void *user_mask, long sizemask, long flags) {} POST_SYSCALL(signalfd4)(long res, long ufd, kernel_sigset_t *user_mask, long sizemask, long flags) { if (res >= 0) { if (user_mask) POST_WRITE(user_mask, sizemask); } } PRE_SYSCALL(timerfd_create)(long clockid, long flags) {} POST_SYSCALL(timerfd_create)(long res, long clockid, long flags) {} PRE_SYSCALL(timerfd_settime)(long ufd, long flags, const void *utmr, void *otmr) { if (utmr) PRE_READ(utmr, struct_itimerspec_sz); } POST_SYSCALL(timerfd_settime)(long res, long ufd, long flags, const void *utmr, void *otmr) { if (res >= 0) { if (otmr) POST_WRITE(otmr, struct_itimerspec_sz); } } PRE_SYSCALL(timerfd_gettime)(long ufd, void *otmr) {} POST_SYSCALL(timerfd_gettime)(long res, long ufd, void *otmr) { if (res >= 0) { if (otmr) POST_WRITE(otmr, struct_itimerspec_sz); } } PRE_SYSCALL(eventfd)(long count) {} POST_SYSCALL(eventfd)(long res, long count) {} PRE_SYSCALL(eventfd2)(long count, long flags) {} POST_SYSCALL(eventfd2)(long res, long count, long flags) {} PRE_SYSCALL(old_readdir)(long arg0, void *arg1, long arg2) {} POST_SYSCALL(old_readdir)(long res, long arg0, void *arg1, long arg2) { // Missing definition of 'struct old_linux_dirent'. } PRE_SYSCALL(pselect6)(long arg0, __sanitizer___kernel_fd_set *arg1, __sanitizer___kernel_fd_set *arg2, __sanitizer___kernel_fd_set *arg3, void *arg4, void *arg5) {} POST_SYSCALL(pselect6)(long res, long arg0, __sanitizer___kernel_fd_set *arg1, __sanitizer___kernel_fd_set *arg2, __sanitizer___kernel_fd_set *arg3, void *arg4, void *arg5) { if (res >= 0) { if (arg1) POST_WRITE(arg1, sizeof(*arg1)); if (arg2) POST_WRITE(arg2, sizeof(*arg2)); if (arg3) POST_WRITE(arg3, sizeof(*arg3)); if (arg4) POST_WRITE(arg4, struct_timespec_sz); } } PRE_SYSCALL(ppoll)(__sanitizer_pollfd *arg0, long arg1, void *arg2, const kernel_sigset_t *arg3, long arg4) { if (arg3) PRE_READ(arg3, arg4); } POST_SYSCALL(ppoll)(long res, __sanitizer_pollfd *arg0, long arg1, void *arg2, const void *arg3, long arg4) { if (res >= 0) { if (arg0) POST_WRITE(arg0, sizeof(*arg0)); if (arg2) POST_WRITE(arg2, struct_timespec_sz); } } PRE_SYSCALL(syncfs)(long fd) {} POST_SYSCALL(syncfs)(long res, long fd) {} PRE_SYSCALL(perf_event_open)(__sanitizer_perf_event_attr *attr_uptr, long pid, long cpu, long group_fd, long flags) { if (attr_uptr) PRE_READ(attr_uptr, attr_uptr->size); } POST_SYSCALL(perf_event_open)(long res, __sanitizer_perf_event_attr *attr_uptr, long pid, long cpu, long group_fd, long flags) {} PRE_SYSCALL(mmap_pgoff)(long addr, long len, long prot, long flags, long fd, long pgoff) {} POST_SYSCALL(mmap_pgoff)(long res, long addr, long len, long prot, long flags, long fd, long pgoff) {} PRE_SYSCALL(old_mmap)(void *arg) {} POST_SYSCALL(old_mmap)(long res, void *arg) {} PRE_SYSCALL(name_to_handle_at)(long dfd, const void *name, void *handle, void *mnt_id, long flag) {} POST_SYSCALL(name_to_handle_at)(long res, long dfd, const void *name, void *handle, void *mnt_id, long flag) {} PRE_SYSCALL(open_by_handle_at)(long mountdirfd, void *handle, long flags) {} POST_SYSCALL(open_by_handle_at)(long res, long mountdirfd, void *handle, long flags) {} PRE_SYSCALL(setns)(long fd, long nstype) {} POST_SYSCALL(setns)(long res, long fd, long nstype) {} PRE_SYSCALL(process_vm_readv)(long pid, const __sanitizer_iovec *lvec, long liovcnt, const void *rvec, long riovcnt, long flags) {} POST_SYSCALL(process_vm_readv)(long res, long pid, const __sanitizer_iovec *lvec, long liovcnt, const void *rvec, long riovcnt, long flags) { if (res >= 0) { if (lvec) kernel_write_iovec(lvec, liovcnt, res); } } PRE_SYSCALL(process_vm_writev)(long pid, const __sanitizer_iovec *lvec, long liovcnt, const void *rvec, long riovcnt, long flags) {} POST_SYSCALL(process_vm_writev)(long res, long pid, const __sanitizer_iovec *lvec, long liovcnt, const void *rvec, long riovcnt, long flags) { if (res >= 0) { if (lvec) kernel_read_iovec(lvec, liovcnt, res); } } PRE_SYSCALL(fork)() { COMMON_SYSCALL_PRE_FORK(); } POST_SYSCALL(fork)(long res) { COMMON_SYSCALL_POST_FORK(res); } PRE_SYSCALL(vfork)() { COMMON_SYSCALL_PRE_FORK(); } POST_SYSCALL(vfork)(long res) { COMMON_SYSCALL_POST_FORK(res); } } // extern "C" #undef PRE_SYSCALL #undef PRE_READ #undef PRE_WRITE #undef POST_SYSCALL #undef POST_READ #undef POST_WRITE #endif // SANITIZER_LINUX Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc (revision 279194) @@ -1,718 +1,731 @@ //===-- sanitizer_coverage.cc ---------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Sanitizer Coverage. // This file implements run-time support for a poor man's coverage tool. // // Compiler instrumentation: // For every interesting basic block the compiler injects the following code: // if (Guard < 0) { // __sanitizer_cov(&Guard); // } // At the module start up time __sanitizer_cov_module_init sets the guards // to consecutive negative numbers (-1, -2, -3, ...). // It's fine to call __sanitizer_cov more than once for a given block. // // Run-time: // - __sanitizer_cov(): record that we've executed the PC (GET_CALLER_PC). // and atomically set Guard to -Guard. // - __sanitizer_cov_dump: dump the coverage data to disk. // For every module of the current process that has coverage data // this will create a file module_name.PID.sancov. The file format is simple: // it's just a sorted sequence of 4-byte offsets in the module. // // Eventually, this coverage implementation should be obsoleted by a more // powerful general purpose Clang/LLVM coverage instrumentation. // Consider this implementation as prototype. // // FIXME: support (or at least test with) dlclose. //===----------------------------------------------------------------------===// #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" #include "sanitizer_libc.h" #include "sanitizer_mutex.h" #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" #include "sanitizer_symbolizer.h" #include "sanitizer_flags.h" static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once. static atomic_uintptr_t coverage_counter; // pc_array is the array containing the covered PCs. // To make the pc_array thread- and async-signal-safe it has to be large enough. // 128M counters "ought to be enough for anybody" (4M on 32-bit). // With coverage_direct=1 in ASAN_OPTIONS, pc_array memory is mapped to a file. // In this mode, __sanitizer_cov_dump does nothing, and CovUpdateMapping() // dump current memory layout to another file. static bool cov_sandboxed = false; static int cov_fd = kInvalidFd; static unsigned int cov_max_block_size = 0; static bool coverage_enabled = false; static const char *coverage_dir; namespace __sanitizer { class CoverageData { public: void Init(); void Enable(); void Disable(); void ReInit(); void BeforeFork(); void AfterFork(int child_pid); void Extend(uptr npcs); void Add(uptr pc, u32 *guard); void IndirCall(uptr caller, uptr callee, uptr callee_cache[], uptr cache_size); void DumpCallerCalleePairs(); void DumpTrace(); ALWAYS_INLINE void TraceBasicBlock(s32 *id); void InitializeGuardArray(s32 *guards); - void InitializeGuards(s32 *guards, uptr n); + void InitializeGuards(s32 *guards, uptr n, const char *module_name); void ReinitializeGuards(); uptr *data(); uptr size(); private: // Maximal size pc array may ever grow. // We MmapNoReserve this space to ensure that the array is contiguous. static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 24, 1 << 27); // The amount file mapping for the pc array is grown by. static const uptr kPcArrayMmapSize = 64 * 1024; // pc_array is allocated with MmapNoReserveOrDie and so it uses only as // much RAM as it really needs. uptr *pc_array; // Index of the first available pc_array slot. atomic_uintptr_t pc_array_index; // Array size. atomic_uintptr_t pc_array_size; // Current file mapped size of the pc array. uptr pc_array_mapped_size; // Descriptor of the file mapped pc array. int pc_fd; // Vector of coverage guard arrays, protected by mu. InternalMmapVectorNoCtor guard_array_vec; + // Vector of module (compilation unit) names. + InternalMmapVectorNoCtor comp_unit_name_vec; + // Caller-Callee (cc) array, size and current index. static const uptr kCcArrayMaxSize = FIRST_32_SECOND_64(1 << 18, 1 << 24); uptr **cc_array; atomic_uintptr_t cc_array_index; atomic_uintptr_t cc_array_size; // Tracing event array, size and current pointer. // We record all events (basic block entries) in a global buffer of u32 // values. Each such value is the index in pc_array. // So far the tracing is highly experimental: // - not thread-safe; // - does not support long traces; // - not tuned for performance. static const uptr kTrEventArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 30); u32 *tr_event_array; uptr tr_event_array_size; u32 *tr_event_pointer; static const uptr kTrPcArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 27); StaticSpinMutex mu; void DirectOpen(); }; static CoverageData coverage_data; void CovUpdateMapping(const char *path, uptr caller_pc = 0); void CoverageData::DirectOpen() { InternalScopedString path(kMaxPathLength); internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.raw", coverage_dir, internal_getpid()); pc_fd = OpenFile(path.data(), true); if (internal_iserror(pc_fd)) { Report(" Coverage: failed to open %s for writing\n", path.data()); Die(); } pc_array_mapped_size = 0; CovUpdateMapping(coverage_dir); } void CoverageData::Init() { pc_fd = kInvalidFd; } void CoverageData::Enable() { if (pc_array) return; pc_array = reinterpret_cast( MmapNoReserveOrDie(sizeof(uptr) * kPcArrayMaxSize, "CovInit")); atomic_store(&pc_array_index, 0, memory_order_relaxed); if (common_flags()->coverage_direct) { atomic_store(&pc_array_size, 0, memory_order_relaxed); } else { atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed); } cc_array = reinterpret_cast(MmapNoReserveOrDie( sizeof(uptr *) * kCcArrayMaxSize, "CovInit::cc_array")); atomic_store(&cc_array_size, kCcArrayMaxSize, memory_order_relaxed); atomic_store(&cc_array_index, 0, memory_order_relaxed); // Allocate tr_event_array with a guard page at the end. tr_event_array = reinterpret_cast(MmapNoReserveOrDie( sizeof(tr_event_array[0]) * kTrEventArrayMaxSize + GetMmapGranularity(), "CovInit::tr_event_array")); Mprotect(reinterpret_cast(&tr_event_array[kTrEventArrayMaxSize]), GetMmapGranularity()); tr_event_array_size = kTrEventArrayMaxSize; tr_event_pointer = tr_event_array; } void CoverageData::InitializeGuardArray(s32 *guards) { Enable(); // Make sure coverage is enabled at this point. s32 n = guards[0]; for (s32 j = 1; j <= n; j++) { uptr idx = atomic_fetch_add(&pc_array_index, 1, memory_order_relaxed); guards[j] = -static_cast(idx + 1); } } void CoverageData::Disable() { if (pc_array) { internal_munmap(pc_array, sizeof(uptr) * kPcArrayMaxSize); pc_array = nullptr; } if (cc_array) { internal_munmap(cc_array, sizeof(uptr *) * kCcArrayMaxSize); cc_array = nullptr; } if (tr_event_array) { internal_munmap(tr_event_array, sizeof(tr_event_array[0]) * kTrEventArrayMaxSize + GetMmapGranularity()); tr_event_array = nullptr; tr_event_pointer = nullptr; } if (pc_fd != kInvalidFd) { internal_close(pc_fd); pc_fd = kInvalidFd; } } void CoverageData::ReinitializeGuards() { // Assuming single thread. atomic_store(&pc_array_index, 0, memory_order_relaxed); for (uptr i = 0; i < guard_array_vec.size(); i++) InitializeGuardArray(guard_array_vec[i]); } void CoverageData::ReInit() { Disable(); if (coverage_enabled) { if (common_flags()->coverage_direct) { // In memory-mapped mode we must extend the new file to the known array // size. uptr size = atomic_load(&pc_array_size, memory_order_relaxed); Enable(); if (size) Extend(size); if (coverage_enabled) CovUpdateMapping(coverage_dir); } else { Enable(); } } // Re-initialize the guards. // We are single-threaded now, no need to grab any lock. CHECK_EQ(atomic_load(&pc_array_index, memory_order_relaxed), 0); ReinitializeGuards(); } void CoverageData::BeforeFork() { mu.Lock(); } void CoverageData::AfterFork(int child_pid) { // We are single-threaded so it's OK to release the lock early. mu.Unlock(); if (child_pid == 0) ReInit(); } // Extend coverage PC array to fit additional npcs elements. void CoverageData::Extend(uptr npcs) { if (!common_flags()->coverage_direct) return; SpinMutexLock l(&mu); uptr size = atomic_load(&pc_array_size, memory_order_relaxed); size += npcs * sizeof(uptr); if (coverage_enabled && size > pc_array_mapped_size) { if (pc_fd == kInvalidFd) DirectOpen(); CHECK_NE(pc_fd, kInvalidFd); uptr new_mapped_size = pc_array_mapped_size; while (size > new_mapped_size) new_mapped_size += kPcArrayMmapSize; CHECK_LE(new_mapped_size, sizeof(uptr) * kPcArrayMaxSize); // Extend the file and map the new space at the end of pc_array. uptr res = internal_ftruncate(pc_fd, new_mapped_size); int err; if (internal_iserror(res, &err)) { Printf("failed to extend raw coverage file: %d\n", err); Die(); } uptr next_map_base = ((uptr)pc_array) + pc_array_mapped_size; void *p = MapWritableFileToMemory((void *)next_map_base, new_mapped_size - pc_array_mapped_size, pc_fd, pc_array_mapped_size); CHECK_EQ((uptr)p, next_map_base); pc_array_mapped_size = new_mapped_size; } atomic_store(&pc_array_size, size, memory_order_release); } -void CoverageData::InitializeGuards(s32 *guards, uptr n) { +void CoverageData::InitializeGuards(s32 *guards, uptr n, + const char *module_name) { // The array 'guards' has n+1 elements, we use the element zero // to store 'n'. CHECK_LT(n, 1 << 30); guards[0] = static_cast(n); InitializeGuardArray(guards); SpinMutexLock l(&mu); + comp_unit_name_vec.push_back(module_name); guard_array_vec.push_back(guards); } // If guard is negative, atomically set it to -guard and store the PC in // pc_array. void CoverageData::Add(uptr pc, u32 *guard) { atomic_uint32_t *atomic_guard = reinterpret_cast(guard); s32 guard_value = atomic_load(atomic_guard, memory_order_relaxed); if (guard_value >= 0) return; atomic_store(atomic_guard, -guard_value, memory_order_relaxed); if (!pc_array) return; uptr idx = -guard_value - 1; if (idx >= atomic_load(&pc_array_index, memory_order_acquire)) return; // May happen after fork when pc_array_index becomes 0. CHECK_LT(idx * sizeof(uptr), atomic_load(&pc_array_size, memory_order_acquire)); pc_array[idx] = pc; atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed); } // Registers a pair caller=>callee. // When a given caller is seen for the first time, the callee_cache is added // to the global array cc_array, callee_cache[0] is set to caller and // callee_cache[1] is set to cache_size. // Then we are trying to add callee to callee_cache [2,cache_size) if it is // not there yet. // If the cache is full we drop the callee (may want to fix this later). void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[], uptr cache_size) { if (!cc_array) return; atomic_uintptr_t *atomic_callee_cache = reinterpret_cast(callee_cache); uptr zero = 0; if (atomic_compare_exchange_strong(&atomic_callee_cache[0], &zero, caller, memory_order_seq_cst)) { uptr idx = atomic_fetch_add(&cc_array_index, 1, memory_order_relaxed); CHECK_LT(idx * sizeof(uptr), atomic_load(&cc_array_size, memory_order_acquire)); callee_cache[1] = cache_size; cc_array[idx] = callee_cache; } CHECK_EQ(atomic_load(&atomic_callee_cache[0], memory_order_relaxed), caller); for (uptr i = 2; i < cache_size; i++) { uptr was = 0; if (atomic_compare_exchange_strong(&atomic_callee_cache[i], &was, callee, memory_order_seq_cst)) { atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed); return; } if (was == callee) // Already have this callee. return; } } uptr *CoverageData::data() { return pc_array; } uptr CoverageData::size() { return atomic_load(&pc_array_index, memory_order_relaxed); } // Block layout for packed file format: header, followed by module name (no // trailing zero), followed by data blob. struct CovHeader { int pid; unsigned int module_name_length; unsigned int data_length; }; static void CovWritePacked(int pid, const char *module, const void *blob, unsigned int blob_size) { if (cov_fd < 0) return; unsigned module_name_length = internal_strlen(module); CovHeader header = {pid, module_name_length, blob_size}; if (cov_max_block_size == 0) { // Writing to a file. Just go ahead. internal_write(cov_fd, &header, sizeof(header)); internal_write(cov_fd, module, module_name_length); internal_write(cov_fd, blob, blob_size); } else { // Writing to a socket. We want to split the data into appropriately sized // blocks. InternalScopedBuffer block(cov_max_block_size); CHECK_EQ((uptr)block.data(), (uptr)(CovHeader *)block.data()); uptr header_size_with_module = sizeof(header) + module_name_length; CHECK_LT(header_size_with_module, cov_max_block_size); unsigned int max_payload_size = cov_max_block_size - header_size_with_module; char *block_pos = block.data(); internal_memcpy(block_pos, &header, sizeof(header)); block_pos += sizeof(header); internal_memcpy(block_pos, module, module_name_length); block_pos += module_name_length; char *block_data_begin = block_pos; const char *blob_pos = (const char *)blob; while (blob_size > 0) { unsigned int payload_size = Min(blob_size, max_payload_size); blob_size -= payload_size; internal_memcpy(block_data_begin, blob_pos, payload_size); blob_pos += payload_size; ((CovHeader *)block.data())->data_length = payload_size; internal_write(cov_fd, block.data(), header_size_with_module + payload_size); } } } // If packed = false: .. (name = module name). // If packed = true and name == 0: ... // If packed = true and name != 0: .. (name is // user-supplied). static int CovOpenFile(bool packed, const char *name, const char *extension = "sancov") { InternalScopedString path(kMaxPathLength); if (!packed) { CHECK(name); path.append("%s/%s.%zd.%s", coverage_dir, name, internal_getpid(), extension); } else { if (!name) path.append("%s/%zd.%s.packed", coverage_dir, internal_getpid(), extension); else path.append("%s/%s.%s.packed", coverage_dir, name, extension); } uptr fd = OpenFile(path.data(), true); if (internal_iserror(fd)) { Report(" SanitizerCoverage: failed to open %s for writing\n", path.data()); return -1; } return fd; } // Dump trace PCs and trace events into two separate files. void CoverageData::DumpTrace() { uptr max_idx = tr_event_pointer - tr_event_array; if (!max_idx) return; auto sym = Symbolizer::GetOrInit(); if (!sym) return; InternalScopedString out(32 << 20); for (uptr i = 0, n = size(); i < n; i++) { const char *module_name = ""; uptr module_address = 0; sym->GetModuleNameAndOffsetForPC(pc_array[i], &module_name, &module_address); out.append("%s 0x%zx\n", module_name, module_address); } int fd = CovOpenFile(false, "trace-points"); if (fd < 0) return; internal_write(fd, out.data(), out.length()); internal_close(fd); + fd = CovOpenFile(false, "trace-compunits"); + if (fd < 0) return; + out.clear(); + for (uptr i = 0; i < comp_unit_name_vec.size(); i++) + out.append("%s\n", comp_unit_name_vec[i]); + internal_write(fd, out.data(), out.length()); + internal_close(fd); + fd = CovOpenFile(false, "trace-events"); if (fd < 0) return; uptr bytes_to_write = max_idx * sizeof(tr_event_array[0]); u8 *event_bytes = reinterpret_cast(tr_event_array); // The trace file could be huge, and may not be written with a single syscall. while (bytes_to_write) { uptr actually_written = internal_write(fd, event_bytes, bytes_to_write); if (actually_written <= bytes_to_write) { bytes_to_write -= actually_written; event_bytes += actually_written; } else { break; } } internal_close(fd); VReport(1, " CovDump: Trace: %zd PCs written\n", size()); VReport(1, " CovDump: Trace: %zd Events written\n", max_idx); } // This function dumps the caller=>callee pairs into a file as a sequence of // lines like "module_name offset". void CoverageData::DumpCallerCalleePairs() { uptr max_idx = atomic_load(&cc_array_index, memory_order_relaxed); if (!max_idx) return; auto sym = Symbolizer::GetOrInit(); if (!sym) return; InternalScopedString out(32 << 20); uptr total = 0; for (uptr i = 0; i < max_idx; i++) { uptr *cc_cache = cc_array[i]; CHECK(cc_cache); uptr caller = cc_cache[0]; uptr n_callees = cc_cache[1]; const char *caller_module_name = ""; uptr caller_module_address = 0; sym->GetModuleNameAndOffsetForPC(caller, &caller_module_name, &caller_module_address); for (uptr j = 2; j < n_callees; j++) { uptr callee = cc_cache[j]; if (!callee) break; total++; const char *callee_module_name = ""; uptr callee_module_address = 0; sym->GetModuleNameAndOffsetForPC(callee, &callee_module_name, &callee_module_address); out.append("%s 0x%zx\n%s 0x%zx\n", caller_module_name, caller_module_address, callee_module_name, callee_module_address); } } int fd = CovOpenFile(false, "caller-callee"); if (fd < 0) return; internal_write(fd, out.data(), out.length()); internal_close(fd); VReport(1, " CovDump: %zd caller-callee pairs written\n", total); } // Record the current PC into the event buffer. // Every event is a u32 value (index in tr_pc_array_index) so we compute // it once and then cache in the provided 'cache' storage. // // This function will eventually be inlined by the compiler. void CoverageData::TraceBasicBlock(s32 *id) { // Will trap here if // 1. coverage is not enabled at run-time. // 2. The array tr_event_array is full. *tr_event_pointer = static_cast(*id - 1); tr_event_pointer++; } static void CovDumpAsBitSet() { if (!common_flags()->coverage_bitset) return; if (!coverage_data.size()) return; int fd = CovOpenFile(/* packed */false, "combined", "bitset-sancov"); if (fd < 0) return; uptr n = coverage_data.size(); uptr n_set_bits = 0; InternalScopedBuffer out(n); for (uptr i = 0; i < n; i++) { uptr pc = coverage_data.data()[i]; out[i] = pc ? '1' : '0'; if (pc) n_set_bits++; } internal_write(fd, out.data(), n); internal_close(fd); VReport(1, " CovDump: bitset of %zd bits written, %zd bits are set\n", n, n_set_bits); } // Dump the coverage on disk. static void CovDump() { if (!coverage_enabled || common_flags()->coverage_direct) return; #if !SANITIZER_WINDOWS if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed)) return; CovDumpAsBitSet(); coverage_data.DumpTrace(); if (!common_flags()->coverage_pcs) return; uptr size = coverage_data.size(); InternalMmapVector offsets(size); uptr *vb = coverage_data.data(); uptr *ve = vb + size; SortArray(vb, size); MemoryMappingLayout proc_maps(/*cache_enabled*/true); uptr mb, me, off, prot; InternalScopedString module(kMaxPathLength); InternalScopedString path(kMaxPathLength); for (int i = 0; proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot); i++) { if ((prot & MemoryMappingLayout::kProtectionExecute) == 0) continue; while (vb < ve && *vb < mb) vb++; if (vb >= ve) break; if (*vb < me) { offsets.clear(); const uptr *old_vb = vb; CHECK_LE(off, *vb); for (; vb < ve && *vb < me; vb++) { uptr diff = *vb - (i ? mb : 0) + off; CHECK_LE(diff, 0xffffffffU); offsets.push_back(static_cast(diff)); } const char *module_name = StripModuleName(module.data()); if (cov_sandboxed) { if (cov_fd >= 0) { CovWritePacked(internal_getpid(), module_name, offsets.data(), offsets.size() * sizeof(u32)); VReport(1, " CovDump: %zd PCs written to packed file\n", vb - old_vb); } } else { // One file per module per process. path.clear(); path.append("%s/%s.%zd.sancov", coverage_dir, module_name, internal_getpid()); int fd = CovOpenFile(false /* packed */, module_name); if (fd > 0) { internal_write(fd, offsets.data(), offsets.size() * sizeof(u32)); internal_close(fd); VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), vb - old_vb); } } } } if (cov_fd >= 0) internal_close(cov_fd); coverage_data.DumpCallerCalleePairs(); #endif // !SANITIZER_WINDOWS } void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { if (!args) return; if (!coverage_enabled) return; cov_sandboxed = args->coverage_sandboxed; if (!cov_sandboxed) return; cov_fd = args->coverage_fd; cov_max_block_size = args->coverage_max_block_size; if (cov_fd < 0) // Pre-open the file now. The sandbox won't allow us to do it later. cov_fd = CovOpenFile(true /* packed */, 0); } int MaybeOpenCovFile(const char *name) { CHECK(name); if (!coverage_enabled) return -1; return CovOpenFile(true /* packed */, name); } void CovBeforeFork() { coverage_data.BeforeFork(); } void CovAfterFork(int child_pid) { coverage_data.AfterFork(child_pid); } void InitializeCoverage(bool enabled, const char *dir) { if (coverage_enabled) return; // May happen if two sanitizer enable coverage in the same process. coverage_enabled = enabled; coverage_dir = dir; coverage_data.Init(); if (enabled) coverage_data.Enable(); #if !SANITIZER_WINDOWS if (!common_flags()->coverage_direct) Atexit(__sanitizer_cov_dump); #endif } void ReInitializeCoverage(bool enabled, const char *dir) { coverage_enabled = enabled; coverage_dir = dir; coverage_data.ReInit(); } void CoverageUpdateMapping() { if (coverage_enabled) CovUpdateMapping(coverage_dir); } } // namespace __sanitizer extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(u32 *guard) { coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()), guard); } SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_with_check(u32 *guard) { atomic_uint32_t *atomic_guard = reinterpret_cast(guard); if (__sanitizer::atomic_load(atomic_guard, memory_order_relaxed)) __sanitizer_cov(guard); } SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_indir_call16(uptr callee, uptr callee_cache16[]) { coverage_data.IndirCall(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()), callee, callee_cache16, 16); } SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() { coverage_enabled = true; coverage_dir = common_flags()->coverage_dir; coverage_data.Init(); } SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); } -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_module_init(s32 *guards, - uptr npcs) { - coverage_data.InitializeGuards(guards, npcs); +SANITIZER_INTERFACE_ATTRIBUTE void +__sanitizer_cov_module_init(s32 *guards, uptr npcs, const char *module_name) { + coverage_data.InitializeGuards(guards, npcs, module_name); if (!common_flags()->coverage_direct) return; if (SANITIZER_ANDROID && coverage_enabled) { // dlopen/dlclose interceptors do not work on Android, so we rely on // Extend() calls to update .sancov.map. CovUpdateMapping(coverage_dir, GET_CALLER_PC()); } coverage_data.Extend(npcs); } SANITIZER_INTERFACE_ATTRIBUTE sptr __sanitizer_maybe_open_cov_file(const char *name) { return MaybeOpenCovFile(name); } SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_total_unique_coverage() { return atomic_load(&coverage_counter, memory_order_relaxed); } SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_trace_func_enter(s32 *id) { coverage_data.TraceBasicBlock(id); } SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_trace_basic_block(s32 *id) { coverage_data.TraceBasicBlock(id); } SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_reset_coverage() { coverage_data.ReinitializeGuards(); internal_bzero_aligned16( coverage_data.data(), RoundUpTo(coverage_data.size() * sizeof(coverage_data.data()[0]), 16)); } SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_coverage_guards(uptr **data) { *data = coverage_data.data(); return coverage_data.size(); } } // extern "C" Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h (revision 279194) @@ -1,121 +1,121 @@ //===-- sanitizer_flag_parser.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/AddressSanitizer runtime. // //===----------------------------------------------------------------------===// #ifndef SANITIZER_FLAG_REGISTRY_H #define SANITIZER_FLAG_REGISTRY_H #include "sanitizer_internal_defs.h" #include "sanitizer_libc.h" #include "sanitizer_common.h" namespace __sanitizer { class FlagHandlerBase { public: virtual bool Parse(const char *value) { return false; } }; template class FlagHandler : public FlagHandlerBase { T *t_; public: explicit FlagHandler(T *t) : t_(t) {} - bool Parse(const char *value); + bool Parse(const char *value) final; }; template <> inline bool FlagHandler::Parse(const char *value) { if (internal_strcmp(value, "0") == 0 || internal_strcmp(value, "no") == 0 || internal_strcmp(value, "false") == 0) { *t_ = false; return true; } if (internal_strcmp(value, "1") == 0 || internal_strcmp(value, "yes") == 0 || internal_strcmp(value, "true") == 0) { *t_ = true; return true; } Printf("ERROR: Invalid value for bool option: '%s'\n", value); return false; } template <> inline bool FlagHandler::Parse(const char *value) { *t_ = internal_strdup(value); return true; } template <> inline bool FlagHandler::Parse(const char *value) { char *value_end; *t_ = internal_simple_strtoll(value, &value_end, 10); bool ok = *value_end == 0; if (!ok) Printf("ERROR: Invalid value for int option: '%s'\n", value); return ok; } template <> inline bool FlagHandler::Parse(const char *value) { char *value_end; *t_ = internal_simple_strtoll(value, &value_end, 10); bool ok = *value_end == 0; if (!ok) Printf("ERROR: Invalid value for uptr option: '%s'\n", value); return ok; } class FlagParser { static const int kMaxFlags = 200; struct Flag { const char *name; const char *desc; FlagHandlerBase *handler; } *flags_; int n_flags_; const char *buf_; uptr pos_; public: FlagParser(); void RegisterHandler(const char *name, FlagHandlerBase *handler, const char *desc); void ParseString(const char *s); void PrintFlagDescriptions(); static LowLevelAllocator Alloc; private: void fatal_error(const char *err); bool is_space(char c); void skip_whitespace(); void parse_flags(); void parse_flag(); bool run_handler(const char *name, const char *value); char *ll_strndup(const char *s, uptr n); }; template static void RegisterFlag(FlagParser *parser, const char *name, const char *desc, T *var) { FlagHandler *fh = new (FlagParser::Alloc) FlagHandler(var); // NOLINT parser->RegisterHandler(name, fh, desc); } void ReportUnrecognizedFlags(); } // namespace __sanitizer #endif // SANITIZER_FLAG_REGISTRY_H Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.cc (revision 279194) @@ -1,87 +1,87 @@ //===-- sanitizer_flags.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 ThreadSanitizer/AddressSanitizer runtime. // //===----------------------------------------------------------------------===// #include "sanitizer_flags.h" #include "sanitizer_common.h" #include "sanitizer_libc.h" #include "sanitizer_list.h" #include "sanitizer_flag_parser.h" namespace __sanitizer { CommonFlags common_flags_dont_use; struct FlagDescription { const char *name; const char *description; FlagDescription *next; }; IntrusiveList flag_descriptions; // If set, the tool will install its own SEGV signal handler by default. #ifndef SANITIZER_NEEDS_SEGV # define SANITIZER_NEEDS_SEGV 1 #endif void CommonFlags::SetDefaults() { #define COMMON_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; #include "sanitizer_flags.inc" #undef COMMON_FLAG } void CommonFlags::CopyFrom(const CommonFlags &other) { internal_memcpy(this, &other, sizeof(*this)); } class FlagHandlerInclude : public FlagHandlerBase { static const uptr kMaxIncludeSize = 1 << 15; FlagParser *parser_; public: explicit FlagHandlerInclude(FlagParser *parser) : parser_(parser) {} - bool Parse(const char *value) { + bool Parse(const char *value) final { char *data; uptr data_mapped_size; int err; uptr len = ReadFileToBuffer(value, &data, &data_mapped_size, Max(kMaxIncludeSize, GetPageSizeCached()), &err); if (!len) { Printf("Failed to read options from '%s': error %d\n", value, err); return false; } parser_->ParseString(data); UnmapOrDie(data, data_mapped_size); return true; } }; void RegisterIncludeFlag(FlagParser *parser, CommonFlags *cf) { FlagHandlerInclude *fh_include = new (FlagParser::Alloc) FlagHandlerInclude(parser); // NOLINT parser->RegisterHandler("include", fh_include, "read more options from the given file"); } void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) { #define COMMON_FLAG(Type, Name, DefaultValue, Description) \ RegisterFlag(parser, #Name, Description, &cf->Name); #include "sanitizer_flags.inc" #undef COMMON_FLAG RegisterIncludeFlag(parser, cf); } } // namespace __sanitizer Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc (revision 279194) @@ -1,149 +1,148 @@ //===-- sanitizer_flags.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 describes common flags available in all sanitizers. // //===----------------------------------------------------------------------===// #ifndef COMMON_FLAG #error "Define COMMON_FLAG prior to including this file!" #endif // COMMON_FLAG(Type, Name, DefaultValue, Description) // Supported types: bool, const char *, int, uptr. // Default value must be a compile-time constant. // Description must be a string literal. COMMON_FLAG( bool, symbolize, true, "If set, use the online symbolizer from common sanitizer runtime to turn " "virtual addresses to file/line locations.") COMMON_FLAG( const char *, external_symbolizer_path, 0, "Path to external symbolizer. If empty, the tool will search $PATH for " "the symbolizer.") COMMON_FLAG( bool, allow_addr2line, false, "If set, allows online symbolizer to run addr2line binary to symbolize " "stack traces (addr2line will only be used if llvm-symbolizer binary is " "unavailable.") COMMON_FLAG(const char *, strip_path_prefix, "", "Strips this prefix from file paths in error reports.") COMMON_FLAG(bool, fast_unwind_on_check, false, "If available, use the fast frame-pointer-based unwinder on " "internal CHECK failures.") COMMON_FLAG(bool, fast_unwind_on_fatal, false, "If available, use the fast frame-pointer-based unwinder on fatal " "errors.") COMMON_FLAG(bool, fast_unwind_on_malloc, true, "If available, use the fast frame-pointer-based unwinder on " "malloc/free.") COMMON_FLAG(bool, handle_ioctl, false, "Intercept and handle ioctl requests.") COMMON_FLAG(int, malloc_context_size, 1, "Max number of stack frames kept for each allocation/deallocation.") COMMON_FLAG( const char *, log_path, "stderr", "Write logs to \"log_path.pid\". The special values are \"stdout\" and " "\"stderr\". The default is \"stderr\".") COMMON_FLAG( int, verbosity, 0, "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).") COMMON_FLAG(bool, detect_leaks, true, "Enable memory leak detection.") COMMON_FLAG( bool, leak_check_at_exit, true, "Invoke leak checking in an atexit handler. Has no effect if " "detect_leaks=false, or if __lsan_do_leak_check() is called before the " "handler has a chance to run.") COMMON_FLAG(bool, allocator_may_return_null, false, "If false, the allocator will crash instead of returning 0 on " "out-of-memory.") COMMON_FLAG(bool, print_summary, true, "If false, disable printing error summaries in addition to error " "reports.") COMMON_FLAG(bool, check_printf, true, "Check printf arguments.") COMMON_FLAG(bool, handle_segv, SANITIZER_NEEDS_SEGV, "If set, registers the tool's custom SEGV handler (both SIGBUS and " "SIGSEGV on OSX).") COMMON_FLAG(bool, allow_user_segv_handler, false, "If set, allows user to register a SEGV handler even if the tool " "registers one.") COMMON_FLAG(bool, use_sigaltstack, true, "If set, uses alternate stack for signal handling.") COMMON_FLAG(bool, detect_deadlocks, false, "If set, deadlock detection is enabled.") COMMON_FLAG( uptr, clear_shadow_mmap_threshold, 64 * 1024, "Large shadow regions are zero-filled using mmap(NORESERVE) instead of " "memset(). This is the threshold size in bytes.") COMMON_FLAG(const char *, color, "auto", "Colorize reports: (always|never|auto).") COMMON_FLAG( bool, legacy_pthread_cond, false, "Enables support for dynamic libraries linked with libpthread 2.2.5.") COMMON_FLAG(bool, intercept_tls_get_addr, false, "Intercept __tls_get_addr.") COMMON_FLAG(bool, help, false, "Print the flag descriptions.") COMMON_FLAG(uptr, mmap_limit_mb, 0, "Limit the amount of mmap-ed memory (excluding shadow) in Mb; " "not a user-facing flag, used mosly for testing the tools") COMMON_FLAG(uptr, hard_rss_limit_mb, 0, "Hard RSS limit in Mb." " If non-zero, a background thread is spawned at startup" " which periodically reads RSS and aborts the process if the" " limit is reached") COMMON_FLAG(uptr, soft_rss_limit_mb, 0, "Soft RSS limit in Mb." " If non-zero, a background thread is spawned at startup" " which periodically reads RSS. If the limit is reached" " all subsequent malloc/new calls will fail or return NULL" " (depending on the value of allocator_may_return_null)" " until the RSS goes below the soft limit." " This limit does not affect memory allocations other than" " malloc/new.") COMMON_FLAG(bool, can_use_proc_maps_statm, true, "If false, do not attempt to read /proc/maps/statm." " Mostly useful for testing sanitizers.") COMMON_FLAG( bool, coverage, false, "If set, coverage information will be dumped at program shutdown (if the " "coverage instrumentation was enabled at compile time).") // On by default, but works only if coverage == true. COMMON_FLAG(bool, coverage_pcs, true, "If set (and if 'coverage' is set too), the coverage information " "will be dumped as a set of PC offsets for every module.") COMMON_FLAG(bool, coverage_bitset, false, "If set (and if 'coverage' is set too), the coverage information " "will also be dumped as a bitset to a separate file.") COMMON_FLAG(bool, coverage_direct, SANITIZER_ANDROID, "If set, coverage information will be dumped directly to a memory " "mapped file. This way data is not lost even if the process is " "suddenly killed.") COMMON_FLAG(const char *, coverage_dir, ".", "Target directory for coverage dumps. Defaults to the current " "directory.") COMMON_FLAG(bool, full_address_space, false, "Sanitize complete address space; " "by default kernel area on 32-bit platforms will not be sanitized") -COMMON_FLAG(const char *, suppressions, "", "Suppressions file name.") COMMON_FLAG(bool, print_suppressions, true, "Print matched suppressions at exit.") COMMON_FLAG( bool, disable_coredump, (SANITIZER_WORDSIZE == 64), "Disable core dumping. By default, disable_core=1 on 64-bit to avoid " "dumping a 16T+ core file. Ignored on OSes that don't dump core by" "default and for sanitizers that don't reserve lots of virtual memory.") COMMON_FLAG(bool, use_madv_dontdump, true, "If set, instructs kernel to not store the (huge) shadow " "in core file.") COMMON_FLAG(bool, symbolize_inline_frames, true, "Print inlined frames in stacktraces. Defaults to true.") COMMON_FLAG(const char *, stack_trace_format, "DEFAULT", "Format string used to render stack frames. " "See sanitizer_stacktrace_printer.h for the format description. " "Use DEFAULT to get default format.") COMMON_FLAG(bool, no_huge_pages_for_shadow, true, "If true, the shadow is not allowed to use huge pages. ") Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h (nonexistent) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h (revision 279194) @@ -0,0 +1,58 @@ +//===-- sanitizer_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 shared between run-time libraries of sanitizers. +// +// This header declares the sanitizer runtime interface functions. +// The runtime library has to define these functions so the instrumented program +// could call them. +// +// See also include/sanitizer/common_interface_defs.h +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_INTERFACE_INTERNAL_H +#define SANITIZER_INTERFACE_INTERNAL_H + +#include "sanitizer_internal_defs.h" + +extern "C" { + // Tell the tools to write their reports to "path." instead of stderr. + // The special values are "stdout" and "stderr". + SANITIZER_INTERFACE_ATTRIBUTE + void __sanitizer_set_report_path(const char *path); + + typedef struct { + int coverage_sandboxed; + __sanitizer::sptr coverage_fd; + unsigned int coverage_max_block_size; + } __sanitizer_sandbox_arguments; + + // Notify the tools that the sandbox is going to be turned on. + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void + __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args); + + // This function is called by the tool when it has just finished reporting + // an error. 'error_summary' is a one-line string that summarizes + // the error message. This function can be overridden by the client. + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + void __sanitizer_report_error_summary(const char *error_summary); + + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump(); + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init(); + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(__sanitizer::u32 *guard); + SANITIZER_INTERFACE_ATTRIBUTE + void __sanitizer_annotate_contiguous_container(const void *beg, + const void *end, + const void *old_mid, + const void *new_mid); + SANITIZER_INTERFACE_ATTRIBUTE + int __sanitizer_verify_contiguous_container(const void *beg, const void *mid, + const void *end); +} // extern "C" + +#endif // SANITIZER_INTERFACE_INTERNAL_H Property changes on: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.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/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h (revision 279194) @@ -1,335 +1,300 @@ //===-- sanitizer_internal_defs.h -------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is shared between AddressSanitizer and ThreadSanitizer. // It contains macro used in run-time libraries code. //===----------------------------------------------------------------------===// #ifndef SANITIZER_DEFS_H #define SANITIZER_DEFS_H #include "sanitizer_platform.h" #ifndef SANITIZER_DEBUG # define SANITIZER_DEBUG 0 #endif // Only use SANITIZER_*ATTRIBUTE* before the function return type! #if SANITIZER_WINDOWS # define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllexport) // FIXME find out what we need on Windows, if anything. # define SANITIZER_WEAK_ATTRIBUTE #elif defined(SANITIZER_GO) # define SANITIZER_INTERFACE_ATTRIBUTE # define SANITIZER_WEAK_ATTRIBUTE #else # define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default"))) # define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak)) #endif #if SANITIZER_LINUX && !defined(SANITIZER_GO) # define SANITIZER_SUPPORTS_WEAK_HOOKS 1 #else # define SANITIZER_SUPPORTS_WEAK_HOOKS 0 #endif // We can use .preinit_array section on Linux to call sanitizer initialization // functions very early in the process startup (unless PIC macro is defined). // FIXME: do we have anything like this on Mac? #if SANITIZER_LINUX && !SANITIZER_ANDROID && !defined(PIC) # define SANITIZER_CAN_USE_PREINIT_ARRAY 1 #else # define SANITIZER_CAN_USE_PREINIT_ARRAY 0 #endif // GCC does not understand __has_feature #if !defined(__has_feature) # define __has_feature(x) 0 #endif // For portability reasons we do not include stddef.h, stdint.h or any other // system header, but we do need some basic types that are not defined // in a portable way by the language itself. namespace __sanitizer { #if defined(_WIN64) // 64-bit Windows uses LLP64 data model. typedef unsigned long long uptr; // NOLINT typedef signed long long sptr; // NOLINT #else typedef unsigned long uptr; // NOLINT typedef signed long sptr; // NOLINT #endif // defined(_WIN64) #if defined(__x86_64__) // Since x32 uses ILP32 data model in 64-bit hardware mode, we must use // 64-bit pointer to unwind stack frame. typedef unsigned long long uhwptr; // NOLINT #else typedef uptr uhwptr; // NOLINT #endif typedef unsigned char u8; typedef unsigned short u16; // NOLINT typedef unsigned int u32; typedef unsigned long long u64; // NOLINT typedef signed char s8; typedef signed short s16; // NOLINT typedef signed int s32; typedef signed long long s64; // NOLINT typedef int fd_t; // WARNING: OFF_T may be different from OS type off_t, depending on the value of // _FILE_OFFSET_BITS. This definition of OFF_T matches the ABI of system calls // like pread and mmap, as opposed to pread64 and mmap64. // FreeBSD, Mac and Linux/x86-64 are special. #if SANITIZER_FREEBSD || SANITIZER_MAC || \ (SANITIZER_LINUX && defined(__x86_64__)) typedef u64 OFF_T; #else typedef uptr OFF_T; #endif typedef u64 OFF64_T; #if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC typedef uptr operator_new_size_type; #else typedef u32 operator_new_size_type; #endif } // namespace __sanitizer -extern "C" { - // Tell the tools to write their reports to "path." instead of stderr. - // The special values are "stdout" and "stderr". - SANITIZER_INTERFACE_ATTRIBUTE - void __sanitizer_set_report_path(const char *path); - - typedef struct { - int coverage_sandboxed; - __sanitizer::sptr coverage_fd; - unsigned int coverage_max_block_size; - } __sanitizer_sandbox_arguments; - - // Notify the tools that the sandbox is going to be turned on. - SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void - __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args); - - // This function is called by the tool when it has just finished reporting - // an error. 'error_summary' is a one-line string that summarizes - // the error message. This function can be overridden by the client. - SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE - void __sanitizer_report_error_summary(const char *error_summary); - - SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump(); - SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init(); - SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(__sanitizer::u32 *guard); - SANITIZER_INTERFACE_ATTRIBUTE - void __sanitizer_annotate_contiguous_container(const void *beg, - const void *end, - const void *old_mid, - const void *new_mid); - SANITIZER_INTERFACE_ATTRIBUTE - int __sanitizer_verify_contiguous_container(const void *beg, const void *mid, - const void *end); -} // extern "C" - using namespace __sanitizer; // NOLINT // ----------- ATTENTION ------------- // This header should NOT include any other headers to avoid portability issues. // Common defs. #define INLINE inline #define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE #define WEAK SANITIZER_WEAK_ATTRIBUTE // Platform-specific defs. #if defined(_MSC_VER) # define ALWAYS_INLINE __forceinline // FIXME(timurrrr): do we need this on Windows? # define ALIAS(x) # define ALIGNED(x) __declspec(align(x)) # define FORMAT(f, a) # define NOINLINE __declspec(noinline) # define NORETURN __declspec(noreturn) # define THREADLOCAL __declspec(thread) # define NOTHROW # define LIKELY(x) (x) # define UNLIKELY(x) (x) # define PREFETCH(x) /* _mm_prefetch(x, _MM_HINT_NTA) */ #else // _MSC_VER # define ALWAYS_INLINE inline __attribute__((always_inline)) # define ALIAS(x) __attribute__((alias(x))) // Please only use the ALIGNED macro before the type. // Using ALIGNED after the variable declaration is not portable! # define ALIGNED(x) __attribute__((aligned(x))) # define FORMAT(f, a) __attribute__((format(printf, f, a))) # define NOINLINE __attribute__((noinline)) # define NORETURN __attribute__((noreturn)) # define THREADLOCAL __thread # define NOTHROW throw() # define LIKELY(x) __builtin_expect(!!(x), 1) # define UNLIKELY(x) __builtin_expect(!!(x), 0) # if defined(__i386__) || defined(__x86_64__) // __builtin_prefetch(x) generates prefetchnt0 on x86 # define PREFETCH(x) __asm__("prefetchnta (%0)" : : "r" (x)) # else # define PREFETCH(x) __builtin_prefetch(x) # endif #endif // _MSC_VER #if !defined(_MSC_VER) || defined(__clang__) # define UNUSED __attribute__((unused)) # define USED __attribute__((used)) #else # define UNUSED # define USED #endif // Unaligned versions of basic types. typedef ALIGNED(1) u16 uu16; typedef ALIGNED(1) u32 uu32; typedef ALIGNED(1) u64 uu64; typedef ALIGNED(1) s16 us16; typedef ALIGNED(1) s32 us32; typedef ALIGNED(1) s64 us64; #if SANITIZER_WINDOWS typedef unsigned long DWORD; // NOLINT typedef DWORD thread_return_t; # define THREAD_CALLING_CONV __stdcall #else // _WIN32 typedef void* thread_return_t; # define THREAD_CALLING_CONV #endif // _WIN32 typedef thread_return_t (THREAD_CALLING_CONV *thread_callback_t)(void* arg); // NOTE: Functions below must be defined in each run-time. namespace __sanitizer { void NORETURN Die(); // FIXME: No, this shouldn't be in the sanitizer interface. SANITIZER_INTERFACE_ATTRIBUTE void NORETURN CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2); } // namespace __sanitizer // Check macro #define RAW_CHECK_MSG(expr, msg) do { \ if (UNLIKELY(!(expr))) { \ RawWrite(msg); \ Die(); \ } \ } while (0) #define RAW_CHECK(expr) RAW_CHECK_MSG(expr, #expr) #define CHECK_IMPL(c1, op, c2) \ do { \ __sanitizer::u64 v1 = (u64)(c1); \ __sanitizer::u64 v2 = (u64)(c2); \ if (UNLIKELY(!(v1 op v2))) \ __sanitizer::CheckFailed(__FILE__, __LINE__, \ "(" #c1 ") " #op " (" #c2 ")", v1, v2); \ } while (false) \ /**/ #define CHECK(a) CHECK_IMPL((a), !=, 0) #define CHECK_EQ(a, b) CHECK_IMPL((a), ==, (b)) #define CHECK_NE(a, b) CHECK_IMPL((a), !=, (b)) #define CHECK_LT(a, b) CHECK_IMPL((a), <, (b)) #define CHECK_LE(a, b) CHECK_IMPL((a), <=, (b)) #define CHECK_GT(a, b) CHECK_IMPL((a), >, (b)) #define CHECK_GE(a, b) CHECK_IMPL((a), >=, (b)) #if SANITIZER_DEBUG #define DCHECK(a) CHECK(a) #define DCHECK_EQ(a, b) CHECK_EQ(a, b) #define DCHECK_NE(a, b) CHECK_NE(a, b) #define DCHECK_LT(a, b) CHECK_LT(a, b) #define DCHECK_LE(a, b) CHECK_LE(a, b) #define DCHECK_GT(a, b) CHECK_GT(a, b) #define DCHECK_GE(a, b) CHECK_GE(a, b) #else #define DCHECK(a) #define DCHECK_EQ(a, b) #define DCHECK_NE(a, b) #define DCHECK_LT(a, b) #define DCHECK_LE(a, b) #define DCHECK_GT(a, b) #define DCHECK_GE(a, b) #endif #define UNREACHABLE(msg) do { \ CHECK(0 && msg); \ Die(); \ } while (0) #define UNIMPLEMENTED() UNREACHABLE("unimplemented") #define COMPILER_CHECK(pred) IMPL_COMPILER_ASSERT(pred, __LINE__) #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) #define IMPL_PASTE(a, b) a##b #define IMPL_COMPILER_ASSERT(pred, line) \ typedef char IMPL_PASTE(assertion_failed_##_, line)[2*(int)(pred)-1] // Limits for integral types. We have to redefine it in case we don't // have stdint.h (like in Visual Studio 9). #undef __INT64_C #undef __UINT64_C #if SANITIZER_WORDSIZE == 64 # define __INT64_C(c) c ## L # define __UINT64_C(c) c ## UL #else # define __INT64_C(c) c ## LL # define __UINT64_C(c) c ## ULL #endif // SANITIZER_WORDSIZE == 64 #undef INT32_MIN #define INT32_MIN (-2147483647-1) #undef INT32_MAX #define INT32_MAX (2147483647) #undef UINT32_MAX #define UINT32_MAX (4294967295U) #undef INT64_MIN #define INT64_MIN (-__INT64_C(9223372036854775807)-1) #undef INT64_MAX #define INT64_MAX (__INT64_C(9223372036854775807)) #undef UINT64_MAX #define UINT64_MAX (__UINT64_C(18446744073709551615)) enum LinkerInitialized { LINKER_INITIALIZED = 0 }; #if !defined(_MSC_VER) || defined(__clang__) # define GET_CALLER_PC() (uptr)__builtin_return_address(0) # define GET_CURRENT_FRAME() (uptr)__builtin_frame_address(0) #else extern "C" void* _ReturnAddress(void); # pragma intrinsic(_ReturnAddress) # define GET_CALLER_PC() (uptr)_ReturnAddress() // CaptureStackBackTrace doesn't need to know BP on Windows. // FIXME: This macro is still used when printing error reports though it's not // clear if the BP value is needed in the ASan reports on Windows. # define GET_CURRENT_FRAME() (uptr)0xDEADBEEF #endif #define HANDLE_EINTR(res, f) \ { \ int rverrno; \ do { \ res = (f); \ } while (internal_iserror(res, &rverrno) && rverrno == EINTR); \ } // Forces the compiler to generate a frame pointer in the function. #define ENABLE_FRAME_POINTER \ do { \ volatile uptr enable_fp; \ enable_fp = GET_CURRENT_FRAME(); \ } while (0) #endif // SANITIZER_DEFS_H Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.cc (revision 279194) @@ -1,106 +1,100 @@ //===-- sanitizer_libignore.cc --------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX #include "sanitizer_libignore.h" #include "sanitizer_flags.h" #include "sanitizer_procmaps.h" namespace __sanitizer { LibIgnore::LibIgnore(LinkerInitialized) { } -void LibIgnore::Init(const SuppressionContext &supp) { +void LibIgnore::AddIgnoredLibrary(const char *name_templ) { BlockingMutexLock lock(&mutex_); - CHECK_EQ(count_, 0); - const uptr n = supp.SuppressionCount(); - for (uptr i = 0; i < n; i++) { - const Suppression *s = supp.SuppressionAt(i); - if (s->type != SuppressionLib) - continue; - if (count_ >= kMaxLibs) { - Report("%s: too many called_from_lib suppressions (max: %d)\n", - SanitizerToolName, kMaxLibs); - Die(); - } - Lib *lib = &libs_[count_++]; - lib->templ = internal_strdup(s->templ); - lib->name = 0; - lib->loaded = false; + if (count_ >= kMaxLibs) { + Report("%s: too many ignored libraries (max: %d)\n", SanitizerToolName, + kMaxLibs); + Die(); } + Lib *lib = &libs_[count_++]; + lib->templ = internal_strdup(name_templ); + lib->name = nullptr; + lib->real_name = nullptr; + lib->loaded = false; } void LibIgnore::OnLibraryLoaded(const char *name) { BlockingMutexLock lock(&mutex_); // Try to match suppressions with symlink target. InternalScopedString buf(kMaxPathLength); if (name != 0 && internal_readlink(name, buf.data(), buf.size() - 1) > 0 && buf[0]) { for (uptr i = 0; i < count_; i++) { Lib *lib = &libs_[i]; if (!lib->loaded && lib->real_name == 0 && TemplateMatch(lib->templ, name)) lib->real_name = internal_strdup(buf.data()); } } // Scan suppressions list and find newly loaded and unloaded libraries. MemoryMappingLayout proc_maps(/*cache_enabled*/false); InternalScopedString module(kMaxPathLength); for (uptr i = 0; i < count_; i++) { Lib *lib = &libs_[i]; bool loaded = false; proc_maps.Reset(); uptr b, e, off, prot; while (proc_maps.Next(&b, &e, &off, module.data(), module.size(), &prot)) { if ((prot & MemoryMappingLayout::kProtectionExecute) == 0) continue; if (TemplateMatch(lib->templ, module.data()) || (lib->real_name != 0 && internal_strcmp(lib->real_name, module.data()) == 0)) { if (loaded) { Report("%s: called_from_lib suppression '%s' is matched against" " 2 libraries: '%s' and '%s'\n", SanitizerToolName, lib->templ, lib->name, module.data()); Die(); } loaded = true; if (lib->loaded) continue; VReport(1, "Matched called_from_lib suppression '%s' against library" " '%s'\n", lib->templ, module.data()); lib->loaded = true; lib->name = internal_strdup(module.data()); const uptr idx = atomic_load(&loaded_count_, memory_order_relaxed); code_ranges_[idx].begin = b; code_ranges_[idx].end = e; atomic_store(&loaded_count_, idx + 1, memory_order_release); } } if (lib->loaded && !loaded) { Report("%s: library '%s' that was matched against called_from_lib" " suppression '%s' is unloaded\n", SanitizerToolName, lib->name, lib->templ); Die(); } } } void LibIgnore::OnLibraryUnloaded() { OnLibraryLoaded(0); } } // namespace __sanitizer #endif // #if SANITIZER_FREEBSD || SANITIZER_LINUX Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_libignore.h (revision 279194) @@ -1,84 +1,83 @@ //===-- sanitizer_libignore.h -----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // LibIgnore allows to ignore all interceptors called from a particular set -// of dynamic libraries. LibIgnore remembers all "called_from_lib" suppressions -// from the provided SuppressionContext; finds code ranges for the libraries; +// of dynamic libraries. LibIgnore can be initialized with several templates +// of names of libraries to be ignored. It finds code ranges for the libraries; // and checks whether the provided PC value belongs to the code ranges. // //===----------------------------------------------------------------------===// #ifndef SANITIZER_LIBIGNORE_H #define SANITIZER_LIBIGNORE_H #include "sanitizer_internal_defs.h" #include "sanitizer_common.h" -#include "sanitizer_suppressions.h" #include "sanitizer_atomic.h" #include "sanitizer_mutex.h" namespace __sanitizer { class LibIgnore { public: explicit LibIgnore(LinkerInitialized); - // Fetches all "called_from_lib" suppressions from the SuppressionContext. - void Init(const SuppressionContext &supp); + // Must be called during initialization. + void AddIgnoredLibrary(const char *name_templ); // Must be called after a new dynamic library is loaded. void OnLibraryLoaded(const char *name); // Must be called after a dynamic library is unloaded. void OnLibraryUnloaded(); // Checks whether the provided PC belongs to one of the ignored libraries. bool IsIgnored(uptr pc) const; private: struct Lib { char *templ; char *name; char *real_name; // target of symlink bool loaded; }; struct LibCodeRange { uptr begin; uptr end; }; static const uptr kMaxLibs = 128; // Hot part: atomic_uintptr_t loaded_count_; LibCodeRange code_ranges_[kMaxLibs]; // Cold part: BlockingMutex mutex_; uptr count_; Lib libs_[kMaxLibs]; // Disallow copying of LibIgnore objects. LibIgnore(const LibIgnore&); // not implemented void operator = (const LibIgnore&); // not implemented }; inline bool LibIgnore::IsIgnored(uptr pc) const { const uptr n = atomic_load(&loaded_count_, memory_order_acquire); for (uptr i = 0; i < n; i++) { if (pc >= code_ranges_[i].begin && pc < code_ranges_[i].end) return true; } return false; } } // namespace __sanitizer #endif // SANITIZER_LIBIGNORE_H Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc (revision 279194) @@ -1,926 +1,933 @@ //===-- sanitizer_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 shared between AddressSanitizer and ThreadSanitizer // run-time libraries and implements linux-specific functions from // sanitizer_libc.h. //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" #include "sanitizer_flags.h" #include "sanitizer_internal_defs.h" #include "sanitizer_libc.h" #include "sanitizer_linux.h" #include "sanitizer_mutex.h" #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" #include "sanitizer_symbolizer.h" #if !SANITIZER_FREEBSD #include #endif // For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat' // format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To // access stat from asm/stat.h, without conflicting with definition in // sys/stat.h, we use this trick. #if defined(__mips64) #include #define stat kernel_stat #include #undef stat #endif #include #include #include #if !SANITIZER_ANDROID #include #endif #include #include #include #include #include #include #include #include #include #include #if SANITIZER_FREEBSD #include #include extern "C" { // must be included after and on // FreeBSD 9.2 and 10.0. #include } extern char **environ; // provided by crt1 #endif // SANITIZER_FREEBSD #if !SANITIZER_ANDROID #include #endif #if SANITIZER_ANDROID #include #include #endif #if SANITIZER_LINUX // struct kernel_timeval { long tv_sec; long tv_usec; }; // is broken on some linux distributions. const int FUTEX_WAIT = 0; const int FUTEX_WAKE = 1; #endif // SANITIZER_LINUX // Are we using 32-bit or 64-bit Linux syscalls? // x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32 // but it still needs to use 64-bit syscalls. #if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_WORDSIZE == 64) # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1 #else # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0 #endif namespace __sanitizer { #if SANITIZER_LINUX && defined(__x86_64__) #include "sanitizer_syscall_linux_x86_64.inc" #else #include "sanitizer_syscall_generic.inc" #endif // --------------- sanitizer_libc.h uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, u64 offset) { #if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd, offset); #else // mmap2 specifies file offset in 4096-byte units. CHECK(IsAligned(offset, 4096)); return internal_syscall(SYSCALL(mmap2), addr, length, prot, flags, fd, offset / 4096); #endif } uptr internal_munmap(void *addr, uptr length) { return internal_syscall(SYSCALL(munmap), (uptr)addr, length); } uptr internal_close(fd_t fd) { return internal_syscall(SYSCALL(close), fd); } uptr internal_open(const char *filename, int flags) { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags); #else return internal_syscall(SYSCALL(open), (uptr)filename, flags); #endif } uptr internal_open(const char *filename, int flags, u32 mode) { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags, mode); #else return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode); #endif } uptr OpenFile(const char *filename, bool write) { return internal_open(filename, write ? O_RDWR | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660); } uptr internal_read(fd_t fd, void *buf, uptr count) { sptr res; HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, count)); return res; } uptr internal_write(fd_t fd, const void *buf, uptr count) { sptr res; HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, count)); return res; } uptr internal_ftruncate(fd_t fd, uptr size) { sptr res; HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, size)); return res; } #if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && !SANITIZER_FREEBSD static void stat64_to_stat(struct stat64 *in, struct stat *out) { internal_memset(out, 0, sizeof(*out)); out->st_dev = in->st_dev; out->st_ino = in->st_ino; out->st_mode = in->st_mode; out->st_nlink = in->st_nlink; out->st_uid = in->st_uid; out->st_gid = in->st_gid; out->st_rdev = in->st_rdev; out->st_size = in->st_size; out->st_blksize = in->st_blksize; out->st_blocks = in->st_blocks; out->st_atime = in->st_atime; out->st_mtime = in->st_mtime; out->st_ctime = in->st_ctime; out->st_ino = in->st_ino; } #endif #if defined(__mips64) static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { internal_memset(out, 0, sizeof(*out)); out->st_dev = in->st_dev; out->st_ino = in->st_ino; out->st_mode = in->st_mode; out->st_nlink = in->st_nlink; out->st_uid = in->st_uid; out->st_gid = in->st_gid; out->st_rdev = in->st_rdev; out->st_size = in->st_size; out->st_blksize = in->st_blksize; out->st_blocks = in->st_blocks; out->st_atime = in->st_atime_nsec; out->st_mtime = in->st_mtime_nsec; out->st_ctime = in->st_ctime_nsec; out->st_ino = in->st_ino; } #endif uptr internal_stat(const char *path, void *buf) { #if SANITIZER_FREEBSD return internal_syscall(SYSCALL(stat), path, buf); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0); #elif SANITIZER_LINUX_USES_64BIT_SYSCALLS # if defined(__mips64) // For mips64, stat syscall fills buffer in the format of kernel_stat struct kernel_stat kbuf; int res = internal_syscall(SYSCALL(stat), path, &kbuf); kernel_stat_to_stat(&kbuf, (struct stat *)buf); return res; # else return internal_syscall(SYSCALL(stat), (uptr)path, (uptr)buf); # endif #else struct stat64 buf64; int res = internal_syscall(SYSCALL(stat64), path, &buf64); stat64_to_stat(&buf64, (struct stat *)buf); return res; #endif } uptr internal_lstat(const char *path, void *buf) { #if SANITIZER_FREEBSD return internal_syscall(SYSCALL(lstat), path, buf); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, AT_SYMLINK_NOFOLLOW); #elif SANITIZER_LINUX_USES_64BIT_SYSCALLS return internal_syscall(SYSCALL(lstat), (uptr)path, (uptr)buf); #else struct stat64 buf64; int res = internal_syscall(SYSCALL(lstat64), path, &buf64); stat64_to_stat(&buf64, (struct stat *)buf); return res; #endif } uptr internal_fstat(fd_t fd, void *buf) { #if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS return internal_syscall(SYSCALL(fstat), fd, (uptr)buf); #else struct stat64 buf64; int res = internal_syscall(SYSCALL(fstat64), fd, &buf64); stat64_to_stat(&buf64, (struct stat *)buf); return res; #endif } uptr internal_filesize(fd_t fd) { struct stat st; if (internal_fstat(fd, &st)) return -1; return (uptr)st.st_size; } uptr internal_dup2(int oldfd, int newfd) { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0); #else return internal_syscall(SYSCALL(dup2), oldfd, newfd); #endif } uptr internal_readlink(const char *path, char *buf, uptr bufsize) { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, bufsize); #else return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize); #endif } uptr internal_unlink(const char *path) { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0); #else return internal_syscall(SYSCALL(unlink), (uptr)path); #endif } uptr internal_rename(const char *oldpath, const char *newpath) { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD, (uptr)newpath); #else return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath); #endif } uptr internal_sched_yield() { return internal_syscall(SYSCALL(sched_yield)); } void internal__exit(int exitcode) { #if SANITIZER_FREEBSD internal_syscall(SYSCALL(exit), exitcode); #else internal_syscall(SYSCALL(exit_group), exitcode); #endif Die(); // Unreachable. } uptr internal_execve(const char *filename, char *const argv[], char *const envp[]) { return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv, (uptr)envp); } // ----------------- sanitizer_common.h bool FileExists(const char *filename) { struct stat st; #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS if (internal_syscall(SYSCALL(newfstatat), AT_FDCWD, filename, &st, 0)) #else if (internal_stat(filename, &st)) #endif return false; // Sanity check: filename is a regular file. return S_ISREG(st.st_mode); } uptr GetTid() { #if SANITIZER_FREEBSD return (uptr)pthread_self(); #else return internal_syscall(SYSCALL(gettid)); #endif } u64 NanoTime() { #if SANITIZER_FREEBSD timeval tv; #else kernel_timeval tv; #endif internal_memset(&tv, 0, sizeof(tv)); internal_syscall(SYSCALL(gettimeofday), (uptr)&tv, 0); return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000; } // Like getenv, but reads env directly from /proc (on Linux) or parses the // 'environ' array (on FreeBSD) and does not use libc. This function should be // called first inside __asan_init. const char *GetEnv(const char *name) { #if SANITIZER_FREEBSD if (::environ != 0) { uptr NameLen = internal_strlen(name); for (char **Env = ::environ; *Env != 0; Env++) { if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=') return (*Env) + NameLen + 1; } } return 0; // Not found. #elif SANITIZER_LINUX static char *environ; static uptr len; static bool inited; if (!inited) { inited = true; uptr environ_size; len = ReadFileToBuffer("/proc/self/environ", &environ, &environ_size, 1 << 26); } if (!environ || len == 0) return 0; uptr namelen = internal_strlen(name); const char *p = environ; while (*p != '\0') { // will happen at the \0\0 that terminates the buffer // proc file has the format NAME=value\0NAME=value\0NAME=value\0... const char* endp = (char*)internal_memchr(p, '\0', len - (p - environ)); if (endp == 0) // this entry isn't NUL terminated return 0; else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match. return p + namelen + 1; // point after = p = endp + 1; } return 0; // Not found. #else #error "Unsupported platform" #endif } extern "C" { SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end; } #if !SANITIZER_GO static void ReadNullSepFileToArray(const char *path, char ***arr, int arr_size) { char *buff; uptr buff_size = 0; *arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray"); ReadFileToBuffer(path, &buff, &buff_size, 1024 * 1024); (*arr)[0] = buff; int count, i; for (count = 1, i = 1; ; i++) { if (buff[i] == 0) { if (buff[i+1] == 0) break; (*arr)[count] = &buff[i+1]; CHECK_LE(count, arr_size - 1); // FIXME: make this more flexible. count++; } } (*arr)[count] = 0; } #endif static void GetArgsAndEnv(char*** argv, char*** envp) { #if !SANITIZER_GO if (&__libc_stack_end) { #endif uptr* stack_end = (uptr*)__libc_stack_end; int argc = *stack_end; *argv = (char**)(stack_end + 1); *envp = (char**)(stack_end + argc + 2); #if !SANITIZER_GO } else { static const int kMaxArgv = 2000, kMaxEnvp = 2000; ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv); ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp); } #endif } void ReExec() { char **argv, **envp; GetArgsAndEnv(&argv, &envp); uptr rv = internal_execve("/proc/self/exe", argv, envp); int rverrno; CHECK_EQ(internal_iserror(rv, &rverrno), true); Printf("execve failed, errno %d\n", rverrno); Die(); } enum MutexState { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 }; BlockingMutex::BlockingMutex() { internal_memset(this, 0, sizeof(*this)); } void BlockingMutex::Lock() { CHECK_EQ(owner_, 0); atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked) return; while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) { #if SANITIZER_FREEBSD _umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0); #else internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT, MtxSleeping, 0, 0, 0); #endif } } void BlockingMutex::Unlock() { atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed); CHECK_NE(v, MtxUnlocked); if (v == MtxSleeping) { #if SANITIZER_FREEBSD _umtx_op(m, UMTX_OP_WAKE, 1, 0, 0); #else internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE, 1, 0, 0, 0); #endif } } void BlockingMutex::CheckLocked() { atomic_uint32_t *m = reinterpret_cast(&opaque_storage_); CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed)); } // ----------------- sanitizer_linux.h // The actual size of this structure is specified by d_reclen. // Note that getdents64 uses a different structure format. We only provide the // 32-bit syscall here. struct linux_dirent { #if SANITIZER_X32 u64 d_ino; u64 d_off; #else unsigned long d_ino; unsigned long d_off; #endif unsigned short d_reclen; char d_name[256]; }; // Syscall wrappers. uptr internal_ptrace(int request, int pid, void *addr, void *data) { return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr, (uptr)data); } uptr internal_waitpid(int pid, int *status, int options) { return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options, 0 /* rusage */); } uptr internal_getpid() { return internal_syscall(SYSCALL(getpid)); } uptr internal_getppid() { return internal_syscall(SYSCALL(getppid)); } uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count); #else return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count); #endif } uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { return internal_syscall(SYSCALL(lseek), fd, offset, whence); } #if SANITIZER_LINUX uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { return internal_syscall(SYSCALL(prctl), option, arg2, arg3, arg4, arg5); } #endif uptr internal_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss) { return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); } int internal_fork() { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(clone), SIGCHLD, 0); #else return internal_syscall(SYSCALL(fork)); #endif } #if SANITIZER_LINUX // Doesn't set sa_restorer, use with caution (see below). int internal_sigaction_norestorer(int signum, const void *act, void *oldact) { __sanitizer_kernel_sigaction_t k_act, k_oldact; internal_memset(&k_act, 0, sizeof(__sanitizer_kernel_sigaction_t)); internal_memset(&k_oldact, 0, sizeof(__sanitizer_kernel_sigaction_t)); const __sanitizer_sigaction *u_act = (const __sanitizer_sigaction *)act; __sanitizer_sigaction *u_oldact = (__sanitizer_sigaction *)oldact; if (u_act) { k_act.handler = u_act->handler; k_act.sigaction = u_act->sigaction; internal_memcpy(&k_act.sa_mask, &u_act->sa_mask, sizeof(__sanitizer_kernel_sigset_t)); k_act.sa_flags = u_act->sa_flags; // FIXME: most often sa_restorer is unset, however the kernel requires it // to point to a valid signal restorer that calls the rt_sigreturn syscall. // If sa_restorer passed to the kernel is NULL, the program may crash upon // signal delivery or fail to unwind the stack in the signal handler. // libc implementation of sigaction() passes its own restorer to // rt_sigaction, so we need to do the same (we'll need to reimplement the // restorers; for x86_64 the restorer address can be obtained from // oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact). k_act.sa_restorer = u_act->sa_restorer; } uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum, (uptr)(u_act ? &k_act : NULL), (uptr)(u_oldact ? &k_oldact : NULL), (uptr)sizeof(__sanitizer_kernel_sigset_t)); if ((result == 0) && u_oldact) { u_oldact->handler = k_oldact.handler; u_oldact->sigaction = k_oldact.sigaction; internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask, sizeof(__sanitizer_kernel_sigset_t)); u_oldact->sa_flags = k_oldact.sa_flags; u_oldact->sa_restorer = k_oldact.sa_restorer; } return result; } #endif // SANITIZER_LINUX uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { #if SANITIZER_FREEBSD return internal_syscall(SYSCALL(sigprocmask), how, set, oldset); #else __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset; return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, (uptr)&k_set->sig[0], (uptr)&k_oldset->sig[0], sizeof(__sanitizer_kernel_sigset_t)); #endif } void internal_sigfillset(__sanitizer_sigset_t *set) { internal_memset(set, 0xff, sizeof(*set)); } #if SANITIZER_LINUX void internal_sigdelset(__sanitizer_sigset_t *set, int signum) { signum -= 1; CHECK_GE(signum, 0); CHECK_LT(signum, sizeof(*set) * 8); __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; const uptr idx = signum / (sizeof(k_set->sig[0]) * 8); const uptr bit = signum % (sizeof(k_set->sig[0]) * 8); k_set->sig[idx] &= ~(1 << bit); } #endif // SANITIZER_LINUX // ThreadLister implementation. ThreadLister::ThreadLister(int pid) : pid_(pid), descriptor_(-1), buffer_(4096), error_(true), entry_((struct linux_dirent *)buffer_.data()), bytes_read_(0) { char task_directory_path[80]; internal_snprintf(task_directory_path, sizeof(task_directory_path), "/proc/%d/task/", pid); uptr openrv = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY); if (internal_iserror(openrv)) { error_ = true; Report("Can't open /proc/%d/task for reading.\n", pid); } else { error_ = false; descriptor_ = openrv; } } int ThreadLister::GetNextTID() { int tid = -1; do { if (error_) return -1; if ((char *)entry_ >= &buffer_[bytes_read_] && !GetDirectoryEntries()) return -1; if (entry_->d_ino != 0 && entry_->d_name[0] >= '0' && entry_->d_name[0] <= '9') { // Found a valid tid. tid = (int)internal_atoll(entry_->d_name); } entry_ = (struct linux_dirent *)(((char *)entry_) + entry_->d_reclen); } while (tid < 0); return tid; } void ThreadLister::Reset() { if (error_ || descriptor_ < 0) return; internal_lseek(descriptor_, 0, SEEK_SET); } ThreadLister::~ThreadLister() { if (descriptor_ >= 0) internal_close(descriptor_); } bool ThreadLister::error() { return error_; } bool ThreadLister::GetDirectoryEntries() { CHECK_GE(descriptor_, 0); CHECK_NE(error_, true); bytes_read_ = internal_getdents(descriptor_, (struct linux_dirent *)buffer_.data(), buffer_.size()); if (internal_iserror(bytes_read_)) { Report("Can't read directory entries from /proc/%d/task.\n", pid_); error_ = true; return false; } else if (bytes_read_ == 0) { return false; } entry_ = (struct linux_dirent *)buffer_.data(); return true; } uptr GetPageSize() { #if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) return EXEC_PAGESIZE; #else return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy. #endif } static char proc_self_exe_cache_str[kMaxPathLength]; static uptr proc_self_exe_cache_len = 0; uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { if (proc_self_exe_cache_len > 0) { // If available, use the cached module name. uptr module_name_len = internal_snprintf(buf, buf_len, "%s", proc_self_exe_cache_str); CHECK_LT(module_name_len, buf_len); return module_name_len; } #if SANITIZER_FREEBSD const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; size_t Size = buf_len; bool IsErr = (sysctl(Mib, 4, buf, &Size, NULL, 0) != 0); int readlink_error = IsErr ? errno : 0; uptr module_name_len = Size; #else uptr module_name_len = internal_readlink( "/proc/self/exe", buf, buf_len); int readlink_error; bool IsErr = internal_iserror(module_name_len, &readlink_error); #endif if (IsErr) { // We can't read /proc/self/exe for some reason, assume the name of the // binary is unknown. Report("WARNING: readlink(\"/proc/self/exe\") failed with errno %d, " "some stack frames may not be symbolized\n", readlink_error); module_name_len = internal_snprintf(buf, buf_len, "/proc/self/exe"); CHECK_LT(module_name_len, buf_len); } return module_name_len; } void CacheBinaryName() { if (!proc_self_exe_cache_len) { proc_self_exe_cache_len = ReadBinaryName(proc_self_exe_cache_str, kMaxPathLength); } } // Match full names of the form /path/to/base_name{-,.}* bool LibraryNameIs(const char *full_name, const char *base_name) { const char *name = full_name; // Strip path. while (*name != '\0') name++; while (name > full_name && *name != '/') name--; if (*name == '/') name++; uptr base_name_length = internal_strlen(base_name); if (internal_strncmp(name, base_name, base_name_length)) return false; return (name[base_name_length] == '-' || name[base_name_length] == '.'); } #if !SANITIZER_ANDROID // Call cb for each region mapped by map. void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) { CHECK_NE(map, nullptr); #if !SANITIZER_FREEBSD typedef ElfW(Phdr) Elf_Phdr; typedef ElfW(Ehdr) Elf_Ehdr; #endif // !SANITIZER_FREEBSD char *base = (char *)map->l_addr; Elf_Ehdr *ehdr = (Elf_Ehdr *)base; char *phdrs = base + ehdr->e_phoff; char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize; // Find the segment with the minimum base so we can "relocate" the p_vaddr // fields. Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC // objects have a non-zero base. uptr preferred_base = (uptr)-1; for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { Elf_Phdr *phdr = (Elf_Phdr *)iter; if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr) preferred_base = (uptr)phdr->p_vaddr; } // Compute the delta from the real base to get a relocation delta. sptr delta = (uptr)base - preferred_base; // Now we can figure out what the loader really mapped. for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) { Elf_Phdr *phdr = (Elf_Phdr *)iter; if (phdr->p_type == PT_LOAD) { uptr seg_start = phdr->p_vaddr + delta; uptr seg_end = seg_start + phdr->p_memsz; // None of these values are aligned. We consider the ragged edges of the // load command as defined, since they are mapped from the file. seg_start = RoundDownTo(seg_start, GetPageSizeCached()); seg_end = RoundUpTo(seg_end, GetPageSizeCached()); cb((void *)seg_start, seg_end - seg_start); } } } #endif #if defined(__x86_64__) && SANITIZER_LINUX // We cannot use glibc's clone wrapper, because it messes with the child // task's TLS. It writes the PID and TID of the child task to its thread // descriptor, but in our case the child task shares the thread descriptor with // the parent (because we don't know how to allocate a new thread // descriptor to keep glibc happy). So the stock version of clone(), when // used with CLONE_VM, would end up corrupting the parent's thread descriptor. uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { long long res; if (!fn || !child_stack) return -EINVAL; CHECK_EQ(0, (uptr)child_stack % 16); child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); ((unsigned long long *)child_stack)[0] = (uptr)fn; ((unsigned long long *)child_stack)[1] = (uptr)arg; register void *r8 __asm__("r8") = newtls; register int *r10 __asm__("r10") = child_tidptr; __asm__ __volatile__( /* %rax = syscall(%rax = SYSCALL(clone), * %rdi = flags, * %rsi = child_stack, * %rdx = parent_tidptr, * %r8 = new_tls, * %r10 = child_tidptr) */ "syscall\n" /* if (%rax != 0) * return; */ "testq %%rax,%%rax\n" "jnz 1f\n" /* In the child. Terminate unwind chain. */ // XXX: We should also terminate the CFI unwind chain // here. Unfortunately clang 3.2 doesn't support the // necessary CFI directives, so we skip that part. "xorq %%rbp,%%rbp\n" /* Call "fn(arg)". */ "popq %%rax\n" "popq %%rdi\n" "call *%%rax\n" /* Call _exit(%rax). */ "movq %%rax,%%rdi\n" "movq %2,%%rax\n" "syscall\n" /* Return to parent. */ "1:\n" : "=a" (res) : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), "S"(child_stack), "D"(flags), "d"(parent_tidptr), "r"(r8), "r"(r10) : "rsp", "memory", "r11", "rcx"); return res; } +#elif defined(__mips__) +// TODO(sagarthakur): clone function is to be rewritten in assembly. +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + return clone(fn, child_stack, flags, arg, parent_tidptr, + newtls, child_tidptr); +} #endif // defined(__x86_64__) && SANITIZER_LINUX #if SANITIZER_ANDROID static atomic_uint8_t android_log_initialized; void AndroidLogInit() { atomic_store(&android_log_initialized, 1, memory_order_release); } // This thing is not, strictly speaking, async signal safe, but it does not seem // to cause any issues. Alternative is writing to log devices directly, but // their location and message format might change in the future, so we'd really // like to avoid that. void AndroidLogWrite(const char *buffer) { if (!atomic_load(&android_log_initialized, memory_order_acquire)) return; char *copy = internal_strdup(buffer); char *p = copy; char *q; // __android_log_write has an implicit message length limit. // Print one line at a time. do { q = internal_strchr(p, '\n'); if (q) *q = '\0'; __android_log_write(ANDROID_LOG_INFO, NULL, p); if (q) p = q + 1; } while (q); InternalFree(copy); } void GetExtraActivationFlags(char *buf, uptr size) { CHECK(size > PROP_VALUE_MAX); __system_property_get("asan.options", buf); } #endif bool IsDeadlySignal(int signum) { return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv; } #ifndef SANITIZER_GO void *internal_start_thread(void(*func)(void *arg), void *arg) { // Start the thread with signals blocked, otherwise it can steal user signals. __sanitizer_sigset_t set, old; internal_sigfillset(&set); internal_sigprocmask(SIG_SETMASK, &set, &old); void *th; real_pthread_create(&th, 0, (void*(*)(void *arg))func, arg); internal_sigprocmask(SIG_SETMASK, &old, 0); return th; } void internal_join_thread(void *th) { real_pthread_join(th, 0); } #else void *internal_start_thread(void (*func)(void *), void *arg) { return 0; } void internal_join_thread(void *th) {} #endif } // namespace __sanitizer #endif // SANITIZER_FREEBSD || SANITIZER_LINUX Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.h (revision 279194) @@ -1,93 +1,93 @@ //===-- sanitizer_linux.h ---------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Linux-specific syscall wrappers and classes. // //===----------------------------------------------------------------------===// #ifndef SANITIZER_LINUX_H #define SANITIZER_LINUX_H #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" #include "sanitizer_platform_limits_posix.h" struct link_map; // Opaque type returned by dlopen(). struct sigaltstack; namespace __sanitizer { // Dirent structure for getdents(). Note that this structure is different from // the one in , which is used by readdir(). struct linux_dirent; // Syscall wrappers. uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count); uptr internal_sigaltstack(const struct sigaltstack* ss, struct sigaltstack* oss); uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset); void internal_sigfillset(__sanitizer_sigset_t *set); // Linux-only syscalls. #if SANITIZER_LINUX uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5); // Used only by sanitizer_stoptheworld. Signal handlers that are actually used // (like the process-wide error reporting SEGV handler) must use // internal_sigaction instead. int internal_sigaction_norestorer(int signum, const void *act, void *oldact); void internal_sigdelset(__sanitizer_sigset_t *set, int signum); -#if defined(__x86_64__) +#if defined(__x86_64__) || defined(__mips__) uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr); #endif #endif // SANITIZER_LINUX // This class reads thread IDs from /proc//task using only syscalls. class ThreadLister { public: explicit ThreadLister(int pid); ~ThreadLister(); // GetNextTID returns -1 if the list of threads is exhausted, or if there has // been an error. int GetNextTID(); void Reset(); bool error(); private: bool GetDirectoryEntries(); int pid_; int descriptor_; InternalScopedBuffer buffer_; bool error_; struct linux_dirent* entry_; int bytes_read_; }; // Exposed for testing. uptr ThreadDescriptorSize(); uptr ThreadSelf(); uptr ThreadSelfOffset(); // Matches a library's file name against a base name (stripping path and version // information). bool LibraryNameIs(const char *full_name, const char *base_name); // Read the name of the current binary from /proc/self/exe. uptr ReadBinaryName(/*out*/char *buf, uptr buf_len); // Cache the value of /proc/self/exe. void CacheBinaryName(); // Call cb for each region mapped by map. void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)); } // namespace __sanitizer #endif // SANITIZER_FREEBSD || SANITIZER_LINUX #endif // SANITIZER_LINUX_H Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc (revision 279194) @@ -1,479 +1,519 @@ //===-- sanitizer_linux_libcdep.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 shared between AddressSanitizer and ThreadSanitizer // run-time libraries and implements linux-specific functions from // sanitizer_libc.h. //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX #include "sanitizer_common.h" #include "sanitizer_flags.h" #include "sanitizer_freebsd.h" #include "sanitizer_linux.h" #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" #include "sanitizer_atomic.h" #include "sanitizer_symbolizer.h" #if SANITIZER_ANDROID || SANITIZER_FREEBSD #include // for dlsym() #endif #include #include #include #if SANITIZER_FREEBSD #include #include #define pthread_getattr_np pthread_attr_get_np #endif #if SANITIZER_LINUX #include #endif #if !SANITIZER_ANDROID #include #include #include #endif namespace __sanitizer { // This function is defined elsewhere if we intercepted pthread_attr_getstack. extern "C" { SANITIZER_WEAK_ATTRIBUTE int real_pthread_attr_getstack(void *attr, void **addr, size_t *size); } // extern "C" static int my_pthread_attr_getstack(void *attr, void **addr, size_t *size) { #if !SANITIZER_GO if (&real_pthread_attr_getstack) return real_pthread_attr_getstack((pthread_attr_t *)attr, addr, size); #endif return pthread_attr_getstack((pthread_attr_t *)attr, addr, size); } SANITIZER_WEAK_ATTRIBUTE int real_sigaction(int signum, const void *act, void *oldact); int internal_sigaction(int signum, const void *act, void *oldact) { #if !SANITIZER_GO if (&real_sigaction) return real_sigaction(signum, act, oldact); #endif return sigaction(signum, (const struct sigaction *)act, (struct sigaction *)oldact); } void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, uptr *stack_bottom) { CHECK(stack_top); CHECK(stack_bottom); if (at_initialization) { // This is the main thread. Libpthread may not be initialized yet. struct rlimit rl; CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0); // Find the mapping that contains a stack variable. MemoryMappingLayout proc_maps(/*cache_enabled*/true); uptr start, end, offset; uptr prev_end = 0; while (proc_maps.Next(&start, &end, &offset, 0, 0, /* protection */0)) { if ((uptr)&rl < end) break; prev_end = end; } CHECK((uptr)&rl >= start && (uptr)&rl < end); // Get stacksize from rlimit, but clip it so that it does not overlap // with other mappings. uptr stacksize = rl.rlim_cur; if (stacksize > end - prev_end) stacksize = end - prev_end; // When running with unlimited stack size, we still want to set some limit. // The unlimited stack size is caused by 'ulimit -s unlimited'. // Also, for some reason, GNU make spawns subprocesses with unlimited stack. if (stacksize > kMaxThreadStackSize) stacksize = kMaxThreadStackSize; *stack_top = end; *stack_bottom = end - stacksize; return; } pthread_attr_t attr; pthread_attr_init(&attr); CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); uptr stacksize = 0; void *stackaddr = 0; my_pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize); pthread_attr_destroy(&attr); CHECK_LE(stacksize, kMaxThreadStackSize); // Sanity check. *stack_top = (uptr)stackaddr + stacksize; *stack_bottom = (uptr)stackaddr; } #if !SANITIZER_GO bool SetEnv(const char *name, const char *value) { void *f = dlsym(RTLD_NEXT, "setenv"); if (f == 0) return false; typedef int(*setenv_ft)(const char *name, const char *value, int overwrite); setenv_ft setenv_f; CHECK_EQ(sizeof(setenv_f), sizeof(f)); internal_memcpy(&setenv_f, &f, sizeof(f)); return setenv_f(name, value, 1) == 0; } #endif bool SanitizerSetThreadName(const char *name) { #ifdef PR_SET_NAME return 0 == prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0); // NOLINT #else return false; #endif } bool SanitizerGetThreadName(char *name, int max_len) { #ifdef PR_GET_NAME char buff[17]; if (prctl(PR_GET_NAME, (unsigned long)buff, 0, 0, 0)) // NOLINT return false; internal_strncpy(name, buff, max_len); name[max_len] = 0; return true; #else return false; #endif } #if !SANITIZER_FREEBSD static uptr g_tls_size; #endif #ifdef __i386__ # define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall)) #else # define DL_INTERNAL_FUNCTION #endif +#if defined(__mips__) +// TlsPreTcbSize includes size of struct pthread_descr and size of tcb +// head structure. It lies before the static tls blocks. +static uptr TlsPreTcbSize() { + const uptr kTcbHead = 16; + const uptr kTlsAlign = 16; + const uptr kTlsPreTcbSize = + (ThreadDescriptorSize() + kTcbHead + kTlsAlign - 1) & ~(kTlsAlign - 1); + InitTlsSize(); + g_tls_size = (g_tls_size + kTlsPreTcbSize + kTlsAlign -1) & ~(kTlsAlign - 1); + return kTlsPreTcbSize; +} +#endif + void InitTlsSize() { #if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION; get_tls_func get_tls; void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info"); CHECK_EQ(sizeof(get_tls), sizeof(get_tls_static_info_ptr)); internal_memcpy(&get_tls, &get_tls_static_info_ptr, sizeof(get_tls_static_info_ptr)); CHECK_NE(get_tls, 0); size_t tls_size = 0; size_t tls_align = 0; get_tls(&tls_size, &tls_align); g_tls_size = tls_size; #endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID } -#if (defined(__x86_64__) || defined(__i386__)) && SANITIZER_LINUX +#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__)) \ + && SANITIZER_LINUX // sizeof(struct thread) from glibc. static atomic_uintptr_t kThreadDescriptorSize; uptr ThreadDescriptorSize() { uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed); if (val) return val; +#if defined(__x86_64__) || defined(__i386__) #ifdef _CS_GNU_LIBC_VERSION char buf[64]; uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf)); if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) { char *end; int minor = internal_simple_strtoll(buf + 8, &end, 10); if (end != buf + 8 && (*end == '\0' || *end == '.')) { /* sizeof(struct thread) values from various glibc versions. */ if (SANITIZER_X32) val = 1728; // Assume only one particular version for x32. else if (minor <= 3) val = FIRST_32_SECOND_64(1104, 1696); else if (minor == 4) val = FIRST_32_SECOND_64(1120, 1728); else if (minor == 5) val = FIRST_32_SECOND_64(1136, 1728); else if (minor <= 9) val = FIRST_32_SECOND_64(1136, 1712); else if (minor == 10) val = FIRST_32_SECOND_64(1168, 1776); else if (minor <= 12) val = FIRST_32_SECOND_64(1168, 2288); else if (minor == 13) val = FIRST_32_SECOND_64(1168, 2304); else val = FIRST_32_SECOND_64(1216, 2304); } if (val) atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed); return val; } #endif +#elif defined(__mips__) + // TODO(sagarthakur): add more values as per different glibc versions. + val = FIRST_32_SECOND_64(1152, 1776); + if (val) + atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed); + return val; +#endif return 0; } // The offset at which pointer to self is located in the thread descriptor. const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16); uptr ThreadSelfOffset() { return kThreadSelfOffset; } uptr ThreadSelf() { uptr descr_addr; # if defined(__i386__) asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset)); # elif defined(__x86_64__) asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset)); +# elif defined(__mips__) + // MIPS uses TLS variant I. The thread pointer (in hardware register $29) + // points to the end of the TCB + 0x7000. The pthread_descr structure is + // immediately in front of the TCB. TlsPreTcbSize() includes the size of the + // TCB and the size of pthread_descr. + const uptr kTlsTcbOffset = 0x7000; + uptr thread_pointer; + asm volatile(".set push;\ + .set mips64r2;\ + rdhwr %0,$29;\ + .set pop" : "=r" (thread_pointer)); + descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize(); # else # error "unsupported CPU arch" # endif return descr_addr; } -#endif // (defined(__x86_64__) || defined(__i386__)) && SANITIZER_LINUX +#endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX #if SANITIZER_FREEBSD static void **ThreadSelfSegbase() { void **segbase = 0; # if defined(__i386__) // sysarch(I386_GET_GSBASE, segbase); __asm __volatile("mov %%gs:0, %0" : "=r" (segbase)); # elif defined(__x86_64__) // sysarch(AMD64_GET_FSBASE, segbase); __asm __volatile("movq %%fs:0, %0" : "=r" (segbase)); # else # error "unsupported CPU arch for FreeBSD platform" # endif return segbase; } uptr ThreadSelf() { return (uptr)ThreadSelfSegbase()[2]; } #endif // SANITIZER_FREEBSD #if !SANITIZER_GO static void GetTls(uptr *addr, uptr *size) { #if SANITIZER_LINUX # if defined(__x86_64__) || defined(__i386__) *addr = ThreadSelf(); *size = GetTlsSize(); *addr -= *size; *addr += ThreadDescriptorSize(); +# elif defined(__mips__) + *addr = ThreadSelf(); + *size = GetTlsSize(); # else *addr = 0; *size = 0; # endif #elif SANITIZER_FREEBSD void** segbase = ThreadSelfSegbase(); *addr = 0; *size = 0; if (segbase != 0) { // tcbalign = 16 // tls_size = round(tls_static_space, tcbalign); // dtv = segbase[1]; // dtv[2] = segbase - tls_static_space; void **dtv = (void**) segbase[1]; *addr = (uptr) dtv[2]; *size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]); } #else # error "Unknown OS" #endif } #endif +#if !SANITIZER_GO uptr GetTlsSize() { #if SANITIZER_FREEBSD uptr addr, size; GetTls(&addr, &size); return size; #else return g_tls_size; #endif } +#endif void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, uptr *tls_addr, uptr *tls_size) { #if SANITIZER_GO // Stub implementation for Go. *stk_addr = *stk_size = *tls_addr = *tls_size = 0; #else GetTls(tls_addr, tls_size); uptr stack_top, stack_bottom; GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); *stk_addr = stack_bottom; *stk_size = stack_top - stack_bottom; if (!main) { // If stack and tls intersect, make them non-intersecting. if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) { CHECK_GT(*tls_addr + *tls_size, *stk_addr); CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size); *stk_size -= *tls_size; *tls_addr = *stk_addr + *stk_size; } } #endif } void AdjustStackSize(void *attr_) { pthread_attr_t *attr = (pthread_attr_t *)attr_; uptr stackaddr = 0; size_t stacksize = 0; my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize); // GLibC will return (0 - stacksize) as the stack address in the case when // stacksize is set, but stackaddr is not. bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0); // We place a lot of tool data into TLS, account for that. const uptr minstacksize = GetTlsSize() + 128*1024; if (stacksize < minstacksize) { if (!stack_set) { if (stacksize != 0) { VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize, minstacksize); pthread_attr_setstacksize(attr, minstacksize); } } else { Printf("Sanitizer: pre-allocated stack size is insufficient: " "%zu < %zu\n", stacksize, minstacksize); Printf("Sanitizer: pthread_create is likely to fail.\n"); } } } #if SANITIZER_ANDROID uptr GetListOfModules(LoadedModule *modules, uptr max_modules, string_predicate_t filter) { MemoryMappingLayout memory_mapping(false); return memory_mapping.DumpListOfModules(modules, max_modules, filter); } #else // SANITIZER_ANDROID # if !SANITIZER_FREEBSD typedef ElfW(Phdr) Elf_Phdr; # elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2 # define Elf_Phdr XElf32_Phdr # define dl_phdr_info xdl_phdr_info # define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b)) # endif struct DlIteratePhdrData { LoadedModule *modules; uptr current_n; bool first; uptr max_n; string_predicate_t filter; }; static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) { DlIteratePhdrData *data = (DlIteratePhdrData*)arg; if (data->current_n == data->max_n) return 0; InternalScopedString module_name(kMaxPathLength); if (data->first) { data->first = false; // First module is the binary itself. ReadBinaryName(module_name.data(), module_name.size()); } else if (info->dlpi_name) { module_name.append("%s", info->dlpi_name); } if (module_name[0] == '\0') return 0; if (data->filter && !data->filter(module_name.data())) return 0; void *mem = &data->modules[data->current_n]; LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(), info->dlpi_addr); data->current_n++; for (int i = 0; i < info->dlpi_phnum; i++) { const Elf_Phdr *phdr = &info->dlpi_phdr[i]; if (phdr->p_type == PT_LOAD) { uptr cur_beg = info->dlpi_addr + phdr->p_vaddr; uptr cur_end = cur_beg + phdr->p_memsz; bool executable = phdr->p_flags & PF_X; cur_module->addAddressRange(cur_beg, cur_end, executable); } } return 0; } uptr GetListOfModules(LoadedModule *modules, uptr max_modules, string_predicate_t filter) { CHECK(modules); DlIteratePhdrData data = {modules, 0, true, max_modules, filter}; dl_iterate_phdr(dl_iterate_phdr_cb, &data); return data.current_n; } #endif // SANITIZER_ANDROID void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { // Some kinds of sandboxes may forbid filesystem access, so we won't be able // to read the file mappings from /proc/self/maps. Luckily, neither the // process will be able to load additional libraries, so it's fine to use the // cached mappings. MemoryMappingLayout::CacheMemoryMappings(); // Same for /proc/self/exe in the symbolizer. #if !SANITIZER_GO Symbolizer::GetOrInit()->PrepareForSandboxing(); CovPrepareForSandboxing(args); #endif } // getrusage does not give us the current RSS, only the max RSS. // Still, this is better than nothing if /proc/self/statm is not available // for some reason, e.g. due to a sandbox. static uptr GetRSSFromGetrusage() { struct rusage usage; if (getrusage(RUSAGE_SELF, &usage)) // Failed, probably due to a sandbox. return 0; return usage.ru_maxrss << 10; // ru_maxrss is in Kb. } uptr GetRSS() { if (!common_flags()->can_use_proc_maps_statm) return GetRSSFromGetrusage(); uptr fd = OpenFile("/proc/self/statm", false); if ((sptr)fd < 0) return GetRSSFromGetrusage(); char buf[64]; uptr len = internal_read(fd, buf, sizeof(buf) - 1); internal_close(fd); if ((sptr)len <= 0) return 0; buf[len] = 0; // The format of the file is: // 1084 89 69 11 0 79 0 // We need the second number which is RSS in pages. char *pos = buf; // Skip the first number. while (*pos >= '0' && *pos <= '9') pos++; // Skip whitespaces. while (!(*pos >= '0' && *pos <= '9') && *pos != 0) pos++; // Read the number. uptr rss = 0; while (*pos >= '0' && *pos <= '9') rss = rss * 10 + *pos++ - '0'; return rss * GetPageSizeCached(); } } // namespace __sanitizer #endif // SANITIZER_FREEBSD || SANITIZER_LINUX Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h (revision 279194) @@ -1,247 +1,247 @@ //===-- sanitizer_platform_interceptors.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 defines macro telling whether sanitizer tools can/should intercept // given library functions on a given platform. // //===----------------------------------------------------------------------===// #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H #define SANITIZER_PLATFORM_INTERCEPTORS_H #include "sanitizer_internal_defs.h" #if !SANITIZER_WINDOWS # define SI_NOT_WINDOWS 1 # include "sanitizer_platform_limits_posix.h" #else # define SI_NOT_WINDOWS 0 #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID # define SI_LINUX_NOT_ANDROID 1 #else # define SI_LINUX_NOT_ANDROID 0 #endif #if SANITIZER_FREEBSD # define SI_FREEBSD 1 #else # define SI_FREEBSD 0 #endif #if SANITIZER_LINUX # define SI_LINUX 1 #else # define SI_LINUX 0 #endif #if SANITIZER_MAC # define SI_MAC 1 #else # define SI_MAC 0 #endif #if SANITIZER_IOS # define SI_IOS 1 #else # define SI_IOS 0 #endif #define SANITIZER_INTERCEPT_STRCMP 1 #define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_MEMCHR 1 #define SANITIZER_INTERCEPT_MEMRCHR SI_FREEBSD || SI_LINUX #define SANITIZER_INTERCEPT_READ SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PREAD SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_WRITE SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PWRITE SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_READV SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_WRITEV SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PREADV SI_FREEBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PRCTL SI_LINUX #define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_STRPTIME SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID #ifndef SANITIZER_INTERCEPT_PRINTF # define SANITIZER_INTERCEPT_PRINTF SI_NOT_WINDOWS # define SANITIZER_INTERCEPT_PRINTF_L SI_FREEBSD # define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID #endif #define SANITIZER_INTERCEPT_FREXP 1 #define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETPWENT \ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETPWENT_R SI_FREEBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SETPWENT SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_CLOCK_GETTIME SI_FREEBSD || SI_LINUX #define SANITIZER_INTERCEPT_GETITIMER SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_TIME SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WAIT SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_INET SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETADDRINFO SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETNAMEINFO SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETSOCKNAME SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETHOSTBYNAME_R SI_FREEBSD || SI_LINUX #define SANITIZER_INTERCEPT_GETHOSTBYNAME2_R SI_FREEBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETHOSTBYADDR_R SI_FREEBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETHOSTENT_R SI_FREEBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETSOCKOPT SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_ACCEPT SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_MODF SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_RECVMSG SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETPEERNAME SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_IOCTL SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_INET_ATON SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SYSINFO SI_LINUX #define SANITIZER_INTERCEPT_READDIR SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTRACE SI_LINUX_NOT_ANDROID && \ - (defined(__i386) || defined (__x86_64)) // NOLINT + (defined(__i386) || defined (__x86_64) || defined (__mips64)) // NOLINT #define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STRTOIMAX SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_MBSTOWCS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_MBSNRTOWCS SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_WCSNRTOMBS \ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_CONFSTR \ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STRERROR SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_STRERROR_R SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCANDIR SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETGROUPS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_POLL SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WORDEXP \ SI_FREEBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGWAIT SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGSETOPS \ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_BACKTRACE SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STATFS SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STATFS64 \ (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STATVFS SI_FREEBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_INITGROUPS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_ETHER_HOST \ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_ETHER_R SI_FREEBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SHMCTL \ ((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) #define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL \ SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING \ SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TMPNAM SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TEMPNAM SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SINCOS SI_LINUX #define SANITIZER_INTERCEPT_REMQUO SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_LGAMMA SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_LGAMMA_R SI_FREEBSD || SI_LINUX #define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_RAND_R SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_ICONV SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TIMES SI_NOT_WINDOWS // FIXME: getline seems to be available on OSX 10.7 #define SANITIZER_INTERCEPT_GETLINE SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD #define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \ SI_FREEBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TLS_GET_ADDR \ SI_FREEBSD || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_LISTXATTR SI_LINUX #define SANITIZER_INTERCEPT_GETXATTR SI_LINUX #define SANITIZER_INTERCEPT_GETRESID SI_LINUX #define SANITIZER_INTERCEPT_GETIFADDRS SI_LINUX_NOT_ANDROID || SI_MAC #define SANITIZER_INTERCEPT_IF_INDEXTONAME SI_LINUX_NOT_ANDROID || SI_MAC #define SANITIZER_INTERCEPT_CAPGET SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_AEABI_MEM SI_LINUX && defined(__arm__) #define SANITIZER_INTERCEPT___BZERO SI_MAC #define SANITIZER_INTERCEPT_FTIME SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TSEARCH SI_LINUX_NOT_ANDROID || SI_MAC #define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_FOPEN SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_OPEN_MEMSTREAM SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \ SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_MAC #define SANITIZER_INTERCEPT_GETPASS SI_LINUX_NOT_ANDROID || SI_MAC #define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_MLOCKX SI_NOT_WINDOWS #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc (revision 279194) @@ -1,1194 +1,1205 @@ //===-- sanitizer_platform_limits_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 Sanitizer common code. // // Sizes and layouts of platform-specific POSIX data structures. //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC // Tests in this file assume that off_t-dependent data structures match the // libc ABI. For example, struct dirent here is what readdir() function (as // exported from libc) returns, and not the user-facing "dirent", which // depends on _FILE_OFFSET_BITS setting. // To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below. #ifdef _FILE_OFFSET_BITS #undef _FILE_OFFSET_BITS #endif #if SANITIZER_FREEBSD #define _WANT_RTENTRY #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if !SANITIZER_ANDROID #include #include #endif #if SANITIZER_LINUX #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif #if SANITIZER_FREEBSD # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include #define _KERNEL // to declare 'shminfo' structure # include #undef _KERNEL #undef INLINE // to avoid clashes with sanitizers' definitions #endif #if SANITIZER_FREEBSD || SANITIZER_IOS #undef IOC_DIRMASK #endif #if SANITIZER_LINUX || SANITIZER_FREEBSD # include # include +# if defined(__mips64) +# include +# endif #endif #if !SANITIZER_ANDROID #include #include #include #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#if defined(__mips64) +# include +#endif #include #include #include #include #include #include #include #include #include #include #include #include #endif // SANITIZER_LINUX && !SANITIZER_ANDROID #if SANITIZER_ANDROID #include #include #include #include #endif #if SANITIZER_LINUX #include #include #include #include #endif // SANITIZER_LINUX #if SANITIZER_MAC #include #include #include #endif // Include these after system headers to avoid name clashes and ambiguities. #include "sanitizer_internal_defs.h" #include "sanitizer_platform_limits_posix.h" namespace __sanitizer { unsigned struct_utsname_sz = sizeof(struct utsname); unsigned struct_stat_sz = sizeof(struct stat); #if !SANITIZER_IOS && !SANITIZER_FREEBSD unsigned struct_stat64_sz = sizeof(struct stat64); #endif // !SANITIZER_IOS && !SANITIZER_FREEBSD unsigned struct_rusage_sz = sizeof(struct rusage); unsigned struct_tm_sz = sizeof(struct tm); unsigned struct_passwd_sz = sizeof(struct passwd); unsigned struct_group_sz = sizeof(struct group); unsigned siginfo_t_sz = sizeof(siginfo_t); unsigned struct_sigaction_sz = sizeof(struct sigaction); unsigned struct_itimerval_sz = sizeof(struct itimerval); unsigned pthread_t_sz = sizeof(pthread_t); unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); unsigned pid_t_sz = sizeof(pid_t); unsigned timeval_sz = sizeof(timeval); unsigned uid_t_sz = sizeof(uid_t); unsigned gid_t_sz = sizeof(gid_t); unsigned mbstate_t_sz = sizeof(mbstate_t); unsigned sigset_t_sz = sizeof(sigset_t); unsigned struct_timezone_sz = sizeof(struct timezone); unsigned struct_tms_sz = sizeof(struct tms); unsigned struct_sigevent_sz = sizeof(struct sigevent); unsigned struct_sched_param_sz = sizeof(struct sched_param); #if SANITIZER_MAC && !SANITIZER_IOS unsigned struct_statfs64_sz = sizeof(struct statfs64); #endif // SANITIZER_MAC && !SANITIZER_IOS #if !SANITIZER_ANDROID unsigned struct_statfs_sz = sizeof(struct statfs); unsigned struct_sockaddr_sz = sizeof(struct sockaddr); unsigned ucontext_t_sz = sizeof(ucontext_t); #endif // !SANITIZER_ANDROID #if SANITIZER_LINUX unsigned struct_epoll_event_sz = sizeof(struct epoll_event); unsigned struct_sysinfo_sz = sizeof(struct sysinfo); unsigned __user_cap_header_struct_sz = sizeof(struct __user_cap_header_struct); unsigned __user_cap_data_struct_sz = sizeof(struct __user_cap_data_struct); unsigned struct_new_utsname_sz = sizeof(struct new_utsname); unsigned struct_old_utsname_sz = sizeof(struct old_utsname); unsigned struct_oldold_utsname_sz = sizeof(struct oldold_utsname); #endif // SANITIZER_LINUX #if SANITIZER_LINUX || SANITIZER_FREEBSD unsigned struct_rlimit_sz = sizeof(struct rlimit); unsigned struct_timespec_sz = sizeof(struct timespec); unsigned struct_utimbuf_sz = sizeof(struct utimbuf); unsigned struct_itimerspec_sz = sizeof(struct itimerspec); #endif // SANITIZER_LINUX || SANITIZER_FREEBSD #if SANITIZER_LINUX && !SANITIZER_ANDROID unsigned struct_ustat_sz = sizeof(struct ustat); unsigned struct_rlimit64_sz = sizeof(struct rlimit64); unsigned struct_statvfs64_sz = sizeof(struct statvfs64); #endif // SANITIZER_LINUX && !SANITIZER_ANDROID #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID unsigned struct_timex_sz = sizeof(struct timex); unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); unsigned struct_mq_attr_sz = sizeof(struct mq_attr); unsigned struct_statvfs_sz = sizeof(struct statvfs); #endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID uptr sig_ign = (uptr)SIG_IGN; uptr sig_dfl = (uptr)SIG_DFL; uptr sa_siginfo = (uptr)SA_SIGINFO; #if SANITIZER_LINUX int e_tabsz = (int)E_TABSZ; #endif #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID unsigned struct_shminfo_sz = sizeof(struct shminfo); unsigned struct_shm_info_sz = sizeof(struct shm_info); int shmctl_ipc_stat = (int)IPC_STAT; int shmctl_ipc_info = (int)IPC_INFO; int shmctl_shm_info = (int)SHM_INFO; int shmctl_shm_stat = (int)SHM_STAT; #endif int map_fixed = MAP_FIXED; int af_inet = (int)AF_INET; int af_inet6 = (int)AF_INET6; uptr __sanitizer_in_addr_sz(int af) { if (af == AF_INET) return sizeof(struct in_addr); else if (af == AF_INET6) return sizeof(struct in6_addr); else return 0; } #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID int glob_nomatch = GLOB_NOMATCH; int glob_altdirfunc = GLOB_ALTDIRFUNC; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID && \ - (defined(__i386) || defined(__x86_64)) + (defined(__i386) || defined(__x86_64) || defined(__mips64)) +#if defined(__mips64) + unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs); + unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t); +#else unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct); unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct); -#ifdef __x86_64 +#endif // __mips64 +#if (defined(__x86_64) || defined(__mips64)) unsigned struct_user_fpxregs_struct_sz = 0; #else unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct); -#endif +#endif // __x86_64 || __mips64 int ptrace_peektext = PTRACE_PEEKTEXT; int ptrace_peekdata = PTRACE_PEEKDATA; int ptrace_peekuser = PTRACE_PEEKUSER; int ptrace_getregs = PTRACE_GETREGS; int ptrace_setregs = PTRACE_SETREGS; int ptrace_getfpregs = PTRACE_GETFPREGS; int ptrace_setfpregs = PTRACE_SETFPREGS; int ptrace_getfpxregs = PTRACE_GETFPXREGS; int ptrace_setfpxregs = PTRACE_SETFPXREGS; int ptrace_geteventmsg = PTRACE_GETEVENTMSG; #if (defined(PTRACE_GETSIGINFO) && defined(PTRACE_SETSIGINFO)) || \ (defined(PT_GETSIGINFO) && defined(PT_SETSIGINFO)) int ptrace_getsiginfo = PTRACE_GETSIGINFO; int ptrace_setsiginfo = PTRACE_SETSIGINFO; #else int ptrace_getsiginfo = -1; int ptrace_setsiginfo = -1; #endif // PTRACE_GETSIGINFO/PTRACE_SETSIGINFO #if defined(PTRACE_GETREGSET) && defined(PTRACE_SETREGSET) int ptrace_getregset = PTRACE_GETREGSET; int ptrace_setregset = PTRACE_SETREGSET; #else int ptrace_getregset = -1; int ptrace_setregset = -1; #endif // PTRACE_GETREGSET/PTRACE_SETREGSET #endif unsigned path_max = PATH_MAX; // ioctl arguments unsigned struct_arpreq_sz = sizeof(struct arpreq); unsigned struct_ifreq_sz = sizeof(struct ifreq); unsigned struct_termios_sz = sizeof(struct termios); unsigned struct_winsize_sz = sizeof(struct winsize); #if SANITIZER_LINUX unsigned struct_cdrom_msf_sz = sizeof(struct cdrom_msf); unsigned struct_cdrom_multisession_sz = sizeof(struct cdrom_multisession); unsigned struct_cdrom_read_audio_sz = sizeof(struct cdrom_read_audio); unsigned struct_cdrom_subchnl_sz = sizeof(struct cdrom_subchnl); unsigned struct_cdrom_ti_sz = sizeof(struct cdrom_ti); unsigned struct_cdrom_tocentry_sz = sizeof(struct cdrom_tocentry); unsigned struct_cdrom_tochdr_sz = sizeof(struct cdrom_tochdr); unsigned struct_cdrom_volctrl_sz = sizeof(struct cdrom_volctrl); unsigned struct_ff_effect_sz = sizeof(struct ff_effect); unsigned struct_floppy_drive_params_sz = sizeof(struct floppy_drive_params); unsigned struct_floppy_drive_struct_sz = sizeof(struct floppy_drive_struct); unsigned struct_floppy_fdc_state_sz = sizeof(struct floppy_fdc_state); unsigned struct_floppy_max_errors_sz = sizeof(struct floppy_max_errors); unsigned struct_floppy_raw_cmd_sz = sizeof(struct floppy_raw_cmd); unsigned struct_floppy_struct_sz = sizeof(struct floppy_struct); unsigned struct_floppy_write_errors_sz = sizeof(struct floppy_write_errors); unsigned struct_format_descr_sz = sizeof(struct format_descr); unsigned struct_hd_driveid_sz = sizeof(struct hd_driveid); unsigned struct_hd_geometry_sz = sizeof(struct hd_geometry); unsigned struct_input_absinfo_sz = sizeof(struct input_absinfo); unsigned struct_input_id_sz = sizeof(struct input_id); unsigned struct_mtpos_sz = sizeof(struct mtpos); unsigned struct_termio_sz = sizeof(struct termio); unsigned struct_vt_consize_sz = sizeof(struct vt_consize); unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes); unsigned struct_vt_stat_sz = sizeof(struct vt_stat); #endif // SANITIZER_LINUX #if SANITIZER_LINUX || SANITIZER_FREEBSD #if SOUND_VERSION >= 0x040000 unsigned struct_copr_buffer_sz = 0; unsigned struct_copr_debug_buf_sz = 0; unsigned struct_copr_msg_sz = 0; #else unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer); unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf); unsigned struct_copr_msg_sz = sizeof(struct copr_msg); #endif unsigned struct_midi_info_sz = sizeof(struct midi_info); unsigned struct_mtget_sz = sizeof(struct mtget); unsigned struct_mtop_sz = sizeof(struct mtop); unsigned struct_rtentry_sz = sizeof(struct rtentry); unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument); unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec); unsigned struct_synth_info_sz = sizeof(struct synth_info); unsigned struct_vt_mode_sz = sizeof(struct vt_mode); #endif // SANITIZER_LINUX || SANITIZER_FREEBSD #if SANITIZER_LINUX && !SANITIZER_ANDROID unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct); unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor); #if EV_VERSION > (0x010000) unsigned struct_input_keymap_entry_sz = sizeof(struct input_keymap_entry); #else unsigned struct_input_keymap_entry_sz = 0; #endif unsigned struct_ipx_config_data_sz = sizeof(struct ipx_config_data); unsigned struct_kbdiacrs_sz = sizeof(struct kbdiacrs); unsigned struct_kbentry_sz = sizeof(struct kbentry); unsigned struct_kbkeycode_sz = sizeof(struct kbkeycode); unsigned struct_kbsentry_sz = sizeof(struct kbsentry); unsigned struct_mtconfiginfo_sz = sizeof(struct mtconfiginfo); unsigned struct_nr_parms_struct_sz = sizeof(struct nr_parms_struct); unsigned struct_scc_modem_sz = sizeof(struct scc_modem); unsigned struct_scc_stat_sz = sizeof(struct scc_stat); unsigned struct_serial_multiport_struct_sz = sizeof(struct serial_multiport_struct); unsigned struct_serial_struct_sz = sizeof(struct serial_struct); unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25); unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc); unsigned struct_unimapinit_sz = sizeof(struct unimapinit); #endif // SANITIZER_LINUX && !SANITIZER_ANDROID #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); #endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID #if !SANITIZER_ANDROID && !SANITIZER_MAC unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); #endif const unsigned IOCTL_NOT_PRESENT = 0; unsigned IOCTL_FIOASYNC = FIOASYNC; unsigned IOCTL_FIOCLEX = FIOCLEX; unsigned IOCTL_FIOGETOWN = FIOGETOWN; unsigned IOCTL_FIONBIO = FIONBIO; unsigned IOCTL_FIONCLEX = FIONCLEX; unsigned IOCTL_FIOSETOWN = FIOSETOWN; unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; unsigned IOCTL_SIOCATMARK = SIOCATMARK; unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; unsigned IOCTL_TIOCCONS = TIOCCONS; unsigned IOCTL_TIOCEXCL = TIOCEXCL; unsigned IOCTL_TIOCGETD = TIOCGETD; unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; unsigned IOCTL_TIOCMBIC = TIOCMBIC; unsigned IOCTL_TIOCMBIS = TIOCMBIS; unsigned IOCTL_TIOCMGET = TIOCMGET; unsigned IOCTL_TIOCMSET = TIOCMSET; unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; unsigned IOCTL_TIOCNXCL = TIOCNXCL; unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; unsigned IOCTL_TIOCPKT = TIOCPKT; unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; unsigned IOCTL_TIOCSETD = TIOCSETD; unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; unsigned IOCTL_TIOCSTI = TIOCSTI; unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; #if ((SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID) unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; #endif #if SANITIZER_LINUX unsigned IOCTL_EVIOCGABS = EVIOCGABS(0); unsigned IOCTL_EVIOCGBIT = EVIOCGBIT(0, 0); unsigned IOCTL_EVIOCGEFFECTS = EVIOCGEFFECTS; unsigned IOCTL_EVIOCGID = EVIOCGID; unsigned IOCTL_EVIOCGKEY = EVIOCGKEY(0); unsigned IOCTL_EVIOCGKEYCODE = EVIOCGKEYCODE; unsigned IOCTL_EVIOCGLED = EVIOCGLED(0); unsigned IOCTL_EVIOCGNAME = EVIOCGNAME(0); unsigned IOCTL_EVIOCGPHYS = EVIOCGPHYS(0); unsigned IOCTL_EVIOCGRAB = EVIOCGRAB; unsigned IOCTL_EVIOCGREP = EVIOCGREP; unsigned IOCTL_EVIOCGSND = EVIOCGSND(0); unsigned IOCTL_EVIOCGSW = EVIOCGSW(0); unsigned IOCTL_EVIOCGUNIQ = EVIOCGUNIQ(0); unsigned IOCTL_EVIOCGVERSION = EVIOCGVERSION; unsigned IOCTL_EVIOCRMFF = EVIOCRMFF; unsigned IOCTL_EVIOCSABS = EVIOCSABS(0); unsigned IOCTL_EVIOCSFF = EVIOCSFF; unsigned IOCTL_EVIOCSKEYCODE = EVIOCSKEYCODE; unsigned IOCTL_EVIOCSREP = EVIOCSREP; unsigned IOCTL_BLKFLSBUF = BLKFLSBUF; unsigned IOCTL_BLKGETSIZE = BLKGETSIZE; unsigned IOCTL_BLKRAGET = BLKRAGET; unsigned IOCTL_BLKRASET = BLKRASET; unsigned IOCTL_BLKROGET = BLKROGET; unsigned IOCTL_BLKROSET = BLKROSET; unsigned IOCTL_BLKRRPART = BLKRRPART; unsigned IOCTL_CDROMAUDIOBUFSIZ = CDROMAUDIOBUFSIZ; unsigned IOCTL_CDROMEJECT = CDROMEJECT; unsigned IOCTL_CDROMEJECT_SW = CDROMEJECT_SW; unsigned IOCTL_CDROMMULTISESSION = CDROMMULTISESSION; unsigned IOCTL_CDROMPAUSE = CDROMPAUSE; unsigned IOCTL_CDROMPLAYMSF = CDROMPLAYMSF; unsigned IOCTL_CDROMPLAYTRKIND = CDROMPLAYTRKIND; unsigned IOCTL_CDROMREADAUDIO = CDROMREADAUDIO; unsigned IOCTL_CDROMREADCOOKED = CDROMREADCOOKED; unsigned IOCTL_CDROMREADMODE1 = CDROMREADMODE1; unsigned IOCTL_CDROMREADMODE2 = CDROMREADMODE2; unsigned IOCTL_CDROMREADRAW = CDROMREADRAW; unsigned IOCTL_CDROMREADTOCENTRY = CDROMREADTOCENTRY; unsigned IOCTL_CDROMREADTOCHDR = CDROMREADTOCHDR; unsigned IOCTL_CDROMRESET = CDROMRESET; unsigned IOCTL_CDROMRESUME = CDROMRESUME; unsigned IOCTL_CDROMSEEK = CDROMSEEK; unsigned IOCTL_CDROMSTART = CDROMSTART; unsigned IOCTL_CDROMSTOP = CDROMSTOP; unsigned IOCTL_CDROMSUBCHNL = CDROMSUBCHNL; unsigned IOCTL_CDROMVOLCTRL = CDROMVOLCTRL; unsigned IOCTL_CDROMVOLREAD = CDROMVOLREAD; unsigned IOCTL_CDROM_GET_UPC = CDROM_GET_UPC; unsigned IOCTL_FDCLRPRM = FDCLRPRM; unsigned IOCTL_FDDEFPRM = FDDEFPRM; unsigned IOCTL_FDFLUSH = FDFLUSH; unsigned IOCTL_FDFMTBEG = FDFMTBEG; unsigned IOCTL_FDFMTEND = FDFMTEND; unsigned IOCTL_FDFMTTRK = FDFMTTRK; unsigned IOCTL_FDGETDRVPRM = FDGETDRVPRM; unsigned IOCTL_FDGETDRVSTAT = FDGETDRVSTAT; unsigned IOCTL_FDGETDRVTYP = FDGETDRVTYP; unsigned IOCTL_FDGETFDCSTAT = FDGETFDCSTAT; unsigned IOCTL_FDGETMAXERRS = FDGETMAXERRS; unsigned IOCTL_FDGETPRM = FDGETPRM; unsigned IOCTL_FDMSGOFF = FDMSGOFF; unsigned IOCTL_FDMSGON = FDMSGON; unsigned IOCTL_FDPOLLDRVSTAT = FDPOLLDRVSTAT; unsigned IOCTL_FDRAWCMD = FDRAWCMD; unsigned IOCTL_FDRESET = FDRESET; unsigned IOCTL_FDSETDRVPRM = FDSETDRVPRM; unsigned IOCTL_FDSETEMSGTRESH = FDSETEMSGTRESH; unsigned IOCTL_FDSETMAXERRS = FDSETMAXERRS; unsigned IOCTL_FDSETPRM = FDSETPRM; unsigned IOCTL_FDTWADDLE = FDTWADDLE; unsigned IOCTL_FDWERRORCLR = FDWERRORCLR; unsigned IOCTL_FDWERRORGET = FDWERRORGET; unsigned IOCTL_HDIO_DRIVE_CMD = HDIO_DRIVE_CMD; unsigned IOCTL_HDIO_GETGEO = HDIO_GETGEO; unsigned IOCTL_HDIO_GET_32BIT = HDIO_GET_32BIT; unsigned IOCTL_HDIO_GET_DMA = HDIO_GET_DMA; unsigned IOCTL_HDIO_GET_IDENTITY = HDIO_GET_IDENTITY; unsigned IOCTL_HDIO_GET_KEEPSETTINGS = HDIO_GET_KEEPSETTINGS; unsigned IOCTL_HDIO_GET_MULTCOUNT = HDIO_GET_MULTCOUNT; unsigned IOCTL_HDIO_GET_NOWERR = HDIO_GET_NOWERR; unsigned IOCTL_HDIO_GET_UNMASKINTR = HDIO_GET_UNMASKINTR; unsigned IOCTL_HDIO_SET_32BIT = HDIO_SET_32BIT; unsigned IOCTL_HDIO_SET_DMA = HDIO_SET_DMA; unsigned IOCTL_HDIO_SET_KEEPSETTINGS = HDIO_SET_KEEPSETTINGS; unsigned IOCTL_HDIO_SET_MULTCOUNT = HDIO_SET_MULTCOUNT; unsigned IOCTL_HDIO_SET_NOWERR = HDIO_SET_NOWERR; unsigned IOCTL_HDIO_SET_UNMASKINTR = HDIO_SET_UNMASKINTR; unsigned IOCTL_MTIOCPOS = MTIOCPOS; unsigned IOCTL_PPPIOCGASYNCMAP = PPPIOCGASYNCMAP; unsigned IOCTL_PPPIOCGDEBUG = PPPIOCGDEBUG; unsigned IOCTL_PPPIOCGFLAGS = PPPIOCGFLAGS; unsigned IOCTL_PPPIOCGUNIT = PPPIOCGUNIT; unsigned IOCTL_PPPIOCGXASYNCMAP = PPPIOCGXASYNCMAP; unsigned IOCTL_PPPIOCSASYNCMAP = PPPIOCSASYNCMAP; unsigned IOCTL_PPPIOCSDEBUG = PPPIOCSDEBUG; unsigned IOCTL_PPPIOCSFLAGS = PPPIOCSFLAGS; unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID; unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU; unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP; unsigned IOCTL_SIOCADDRT = SIOCADDRT; unsigned IOCTL_SIOCDARP = SIOCDARP; unsigned IOCTL_SIOCDELRT = SIOCDELRT; unsigned IOCTL_SIOCDRARP = SIOCDRARP; unsigned IOCTL_SIOCGARP = SIOCGARP; unsigned IOCTL_SIOCGIFENCAP = SIOCGIFENCAP; unsigned IOCTL_SIOCGIFHWADDR = SIOCGIFHWADDR; unsigned IOCTL_SIOCGIFMAP = SIOCGIFMAP; unsigned IOCTL_SIOCGIFMEM = SIOCGIFMEM; unsigned IOCTL_SIOCGIFNAME = SIOCGIFNAME; unsigned IOCTL_SIOCGIFSLAVE = SIOCGIFSLAVE; unsigned IOCTL_SIOCGRARP = SIOCGRARP; unsigned IOCTL_SIOCGSTAMP = SIOCGSTAMP; unsigned IOCTL_SIOCSARP = SIOCSARP; unsigned IOCTL_SIOCSIFENCAP = SIOCSIFENCAP; unsigned IOCTL_SIOCSIFHWADDR = SIOCSIFHWADDR; unsigned IOCTL_SIOCSIFLINK = SIOCSIFLINK; unsigned IOCTL_SIOCSIFMAP = SIOCSIFMAP; unsigned IOCTL_SIOCSIFMEM = SIOCSIFMEM; unsigned IOCTL_SIOCSIFSLAVE = SIOCSIFSLAVE; unsigned IOCTL_SIOCSRARP = SIOCSRARP; # if SOUND_VERSION >= 0x040000 unsigned IOCTL_SNDCTL_COPR_HALT = IOCTL_NOT_PRESENT; unsigned IOCTL_SNDCTL_COPR_LOAD = IOCTL_NOT_PRESENT; unsigned IOCTL_SNDCTL_COPR_RCODE = IOCTL_NOT_PRESENT; unsigned IOCTL_SNDCTL_COPR_RCVMSG = IOCTL_NOT_PRESENT; unsigned IOCTL_SNDCTL_COPR_RDATA = IOCTL_NOT_PRESENT; unsigned IOCTL_SNDCTL_COPR_RESET = IOCTL_NOT_PRESENT; unsigned IOCTL_SNDCTL_COPR_RUN = IOCTL_NOT_PRESENT; unsigned IOCTL_SNDCTL_COPR_SENDMSG = IOCTL_NOT_PRESENT; unsigned IOCTL_SNDCTL_COPR_WCODE = IOCTL_NOT_PRESENT; unsigned IOCTL_SNDCTL_COPR_WDATA = IOCTL_NOT_PRESENT; unsigned IOCTL_SOUND_PCM_READ_BITS = IOCTL_NOT_PRESENT; unsigned IOCTL_SOUND_PCM_READ_CHANNELS = IOCTL_NOT_PRESENT; unsigned IOCTL_SOUND_PCM_READ_FILTER = IOCTL_NOT_PRESENT; unsigned IOCTL_SOUND_PCM_READ_RATE = IOCTL_NOT_PRESENT; unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = IOCTL_NOT_PRESENT; unsigned IOCTL_SOUND_PCM_WRITE_FILTER = IOCTL_NOT_PRESENT; # else // SOUND_VERSION unsigned IOCTL_SNDCTL_COPR_HALT = SNDCTL_COPR_HALT; unsigned IOCTL_SNDCTL_COPR_LOAD = SNDCTL_COPR_LOAD; unsigned IOCTL_SNDCTL_COPR_RCODE = SNDCTL_COPR_RCODE; unsigned IOCTL_SNDCTL_COPR_RCVMSG = SNDCTL_COPR_RCVMSG; unsigned IOCTL_SNDCTL_COPR_RDATA = SNDCTL_COPR_RDATA; unsigned IOCTL_SNDCTL_COPR_RESET = SNDCTL_COPR_RESET; unsigned IOCTL_SNDCTL_COPR_RUN = SNDCTL_COPR_RUN; unsigned IOCTL_SNDCTL_COPR_SENDMSG = SNDCTL_COPR_SENDMSG; unsigned IOCTL_SNDCTL_COPR_WCODE = SNDCTL_COPR_WCODE; unsigned IOCTL_SNDCTL_COPR_WDATA = SNDCTL_COPR_WDATA; unsigned IOCTL_SOUND_PCM_READ_BITS = SOUND_PCM_READ_BITS; unsigned IOCTL_SOUND_PCM_READ_CHANNELS = SOUND_PCM_READ_CHANNELS; unsigned IOCTL_SOUND_PCM_READ_FILTER = SOUND_PCM_READ_FILTER; unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE; unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = SOUND_PCM_WRITE_CHANNELS; unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER; #endif // SOUND_VERSION unsigned IOCTL_TCFLSH = TCFLSH; unsigned IOCTL_TCGETA = TCGETA; unsigned IOCTL_TCGETS = TCGETS; unsigned IOCTL_TCSBRK = TCSBRK; unsigned IOCTL_TCSBRKP = TCSBRKP; unsigned IOCTL_TCSETA = TCSETA; unsigned IOCTL_TCSETAF = TCSETAF; unsigned IOCTL_TCSETAW = TCSETAW; unsigned IOCTL_TCSETS = TCSETS; unsigned IOCTL_TCSETSF = TCSETSF; unsigned IOCTL_TCSETSW = TCSETSW; unsigned IOCTL_TCXONC = TCXONC; unsigned IOCTL_TIOCGLCKTRMIOS = TIOCGLCKTRMIOS; unsigned IOCTL_TIOCGSOFTCAR = TIOCGSOFTCAR; unsigned IOCTL_TIOCINQ = TIOCINQ; unsigned IOCTL_TIOCLINUX = TIOCLINUX; unsigned IOCTL_TIOCSERCONFIG = TIOCSERCONFIG; unsigned IOCTL_TIOCSERGETLSR = TIOCSERGETLSR; unsigned IOCTL_TIOCSERGWILD = TIOCSERGWILD; unsigned IOCTL_TIOCSERSWILD = TIOCSERSWILD; unsigned IOCTL_TIOCSLCKTRMIOS = TIOCSLCKTRMIOS; unsigned IOCTL_TIOCSSOFTCAR = TIOCSSOFTCAR; unsigned IOCTL_VT_DISALLOCATE = VT_DISALLOCATE; unsigned IOCTL_VT_GETSTATE = VT_GETSTATE; unsigned IOCTL_VT_RESIZE = VT_RESIZE; unsigned IOCTL_VT_RESIZEX = VT_RESIZEX; unsigned IOCTL_VT_SENDSIG = VT_SENDSIG; #endif // SANITIZER_LINUX #if SANITIZER_LINUX || SANITIZER_FREEBSD unsigned IOCTL_MTIOCGET = MTIOCGET; unsigned IOCTL_MTIOCTOP = MTIOCTOP; unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE; unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR; unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO; unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME; unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE; unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT; unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT; unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS; unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS; unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND; unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC; unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE; unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET; unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES; unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC; unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI; unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD; unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO; unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL; unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE; unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME; unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT; unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE; unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START; unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP; unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO; unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE; unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM; unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS; unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS; unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD; unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK; unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE; unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN; unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX; unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE; unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1; unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2; unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3; unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD; unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC; unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE; unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN; unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM; unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV; unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK; unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC; unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER; unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS; unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH; unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE; unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME; unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM; unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS; unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD; unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE; unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN; unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX; unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE; unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1; unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2; unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3; unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD; unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC; unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE; unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN; unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM; unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV; unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC; unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER; unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH; unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE; unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME; unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; unsigned IOCTL_VT_GETMODE = VT_GETMODE; unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; unsigned IOCTL_VT_RELDISP = VT_RELDISP; unsigned IOCTL_VT_SETMODE = VT_SETMODE; unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; #endif // SANITIZER_LINUX || SANITIZER_FREEBSD #if SANITIZER_LINUX && !SANITIZER_ANDROID unsigned IOCTL_CYGETDEFTHRESH = CYGETDEFTHRESH; unsigned IOCTL_CYGETDEFTIMEOUT = CYGETDEFTIMEOUT; unsigned IOCTL_CYGETMON = CYGETMON; unsigned IOCTL_CYGETTHRESH = CYGETTHRESH; unsigned IOCTL_CYGETTIMEOUT = CYGETTIMEOUT; unsigned IOCTL_CYSETDEFTHRESH = CYSETDEFTHRESH; unsigned IOCTL_CYSETDEFTIMEOUT = CYSETDEFTIMEOUT; unsigned IOCTL_CYSETTHRESH = CYSETTHRESH; unsigned IOCTL_CYSETTIMEOUT = CYSETTIMEOUT; unsigned IOCTL_EQL_EMANCIPATE = EQL_EMANCIPATE; unsigned IOCTL_EQL_ENSLAVE = EQL_ENSLAVE; unsigned IOCTL_EQL_GETMASTRCFG = EQL_GETMASTRCFG; unsigned IOCTL_EQL_GETSLAVECFG = EQL_GETSLAVECFG; unsigned IOCTL_EQL_SETMASTRCFG = EQL_SETMASTRCFG; unsigned IOCTL_EQL_SETSLAVECFG = EQL_SETSLAVECFG; #if EV_VERSION > (0x010000) unsigned IOCTL_EVIOCGKEYCODE_V2 = EVIOCGKEYCODE_V2; unsigned IOCTL_EVIOCGPROP = EVIOCGPROP(0); unsigned IOCTL_EVIOCSKEYCODE_V2 = EVIOCSKEYCODE_V2; #else unsigned IOCTL_EVIOCGKEYCODE_V2 = IOCTL_NOT_PRESENT; unsigned IOCTL_EVIOCGPROP = IOCTL_NOT_PRESENT; unsigned IOCTL_EVIOCSKEYCODE_V2 = IOCTL_NOT_PRESENT; #endif unsigned IOCTL_FS_IOC_GETFLAGS = FS_IOC_GETFLAGS; unsigned IOCTL_FS_IOC_GETVERSION = FS_IOC_GETVERSION; unsigned IOCTL_FS_IOC_SETFLAGS = FS_IOC_SETFLAGS; unsigned IOCTL_FS_IOC_SETVERSION = FS_IOC_SETVERSION; unsigned IOCTL_GIO_CMAP = GIO_CMAP; unsigned IOCTL_GIO_FONT = GIO_FONT; unsigned IOCTL_GIO_UNIMAP = GIO_UNIMAP; unsigned IOCTL_GIO_UNISCRNMAP = GIO_UNISCRNMAP; unsigned IOCTL_KDADDIO = KDADDIO; unsigned IOCTL_KDDELIO = KDDELIO; unsigned IOCTL_KDGETKEYCODE = KDGETKEYCODE; unsigned IOCTL_KDGKBDIACR = KDGKBDIACR; unsigned IOCTL_KDGKBENT = KDGKBENT; unsigned IOCTL_KDGKBLED = KDGKBLED; unsigned IOCTL_KDGKBMETA = KDGKBMETA; unsigned IOCTL_KDGKBSENT = KDGKBSENT; unsigned IOCTL_KDMAPDISP = KDMAPDISP; unsigned IOCTL_KDSETKEYCODE = KDSETKEYCODE; unsigned IOCTL_KDSIGACCEPT = KDSIGACCEPT; unsigned IOCTL_KDSKBDIACR = KDSKBDIACR; unsigned IOCTL_KDSKBENT = KDSKBENT; unsigned IOCTL_KDSKBLED = KDSKBLED; unsigned IOCTL_KDSKBMETA = KDSKBMETA; unsigned IOCTL_KDSKBSENT = KDSKBSENT; unsigned IOCTL_KDUNMAPDISP = KDUNMAPDISP; unsigned IOCTL_LPABORT = LPABORT; unsigned IOCTL_LPABORTOPEN = LPABORTOPEN; unsigned IOCTL_LPCAREFUL = LPCAREFUL; unsigned IOCTL_LPCHAR = LPCHAR; unsigned IOCTL_LPGETIRQ = LPGETIRQ; unsigned IOCTL_LPGETSTATUS = LPGETSTATUS; unsigned IOCTL_LPRESET = LPRESET; unsigned IOCTL_LPSETIRQ = LPSETIRQ; unsigned IOCTL_LPTIME = LPTIME; unsigned IOCTL_LPWAIT = LPWAIT; unsigned IOCTL_MTIOCGETCONFIG = MTIOCGETCONFIG; unsigned IOCTL_MTIOCSETCONFIG = MTIOCSETCONFIG; unsigned IOCTL_PIO_CMAP = PIO_CMAP; unsigned IOCTL_PIO_FONT = PIO_FONT; unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP; unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR; unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP; unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN; unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST; unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE; unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE = SCSI_IOCTL_TAGGED_ENABLE; unsigned IOCTL_SIOCAIPXITFCRT = SIOCAIPXITFCRT; unsigned IOCTL_SIOCAIPXPRISLT = SIOCAIPXPRISLT; unsigned IOCTL_SIOCAX25ADDUID = SIOCAX25ADDUID; unsigned IOCTL_SIOCAX25DELUID = SIOCAX25DELUID; unsigned IOCTL_SIOCAX25GETPARMS = SIOCAX25GETPARMS; unsigned IOCTL_SIOCAX25GETUID = SIOCAX25GETUID; unsigned IOCTL_SIOCAX25NOUID = SIOCAX25NOUID; unsigned IOCTL_SIOCAX25SETPARMS = SIOCAX25SETPARMS; unsigned IOCTL_SIOCDEVPLIP = SIOCDEVPLIP; unsigned IOCTL_SIOCIPXCFGDATA = SIOCIPXCFGDATA; unsigned IOCTL_SIOCNRDECOBS = SIOCNRDECOBS; unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS; unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL; unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS; unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL; unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI; unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI; unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL; #endif // SANITIZER_LINUX && !SANITIZER_ANDROID #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP; unsigned IOCTL_KDDISABIO = KDDISABIO; unsigned IOCTL_KDENABIO = KDENABIO; unsigned IOCTL_KDGETLED = KDGETLED; unsigned IOCTL_KDGETMODE = KDGETMODE; unsigned IOCTL_KDGKBMODE = KDGKBMODE; unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; unsigned IOCTL_KDMKTONE = KDMKTONE; unsigned IOCTL_KDSETLED = KDSETLED; unsigned IOCTL_KDSETMODE = KDSETMODE; unsigned IOCTL_KDSKBMODE = KDSKBMODE; unsigned IOCTL_KIOCSOUND = KIOCSOUND; unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP; unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE; #endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID const int errno_EINVAL = EINVAL; // EOWNERDEAD is not present in some older platforms. #if defined(EOWNERDEAD) const int errno_EOWNERDEAD = EOWNERDEAD; #else const int errno_EOWNERDEAD = -1; #endif const int si_SEGV_MAPERR = SEGV_MAPERR; const int si_SEGV_ACCERR = SEGV_ACCERR; } // namespace __sanitizer COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned)); CHECK_TYPE_SIZE(pthread_key_t); #if SANITIZER_LINUX // FIXME: We define those on Linux and Mac, but only check on Linux. COMPILER_CHECK(IOC_NRBITS == _IOC_NRBITS); COMPILER_CHECK(IOC_TYPEBITS == _IOC_TYPEBITS); COMPILER_CHECK(IOC_SIZEBITS == _IOC_SIZEBITS); COMPILER_CHECK(IOC_DIRBITS == _IOC_DIRBITS); COMPILER_CHECK(IOC_NRMASK == _IOC_NRMASK); COMPILER_CHECK(IOC_TYPEMASK == _IOC_TYPEMASK); COMPILER_CHECK(IOC_SIZEMASK == _IOC_SIZEMASK); COMPILER_CHECK(IOC_DIRMASK == _IOC_DIRMASK); COMPILER_CHECK(IOC_NRSHIFT == _IOC_NRSHIFT); COMPILER_CHECK(IOC_TYPESHIFT == _IOC_TYPESHIFT); COMPILER_CHECK(IOC_SIZESHIFT == _IOC_SIZESHIFT); COMPILER_CHECK(IOC_DIRSHIFT == _IOC_DIRSHIFT); COMPILER_CHECK(IOC_NONE == _IOC_NONE); COMPILER_CHECK(IOC_WRITE == _IOC_WRITE); COMPILER_CHECK(IOC_READ == _IOC_READ); COMPILER_CHECK(EVIOC_ABS_MAX == ABS_MAX); COMPILER_CHECK(EVIOC_EV_MAX == EV_MAX); COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678)); COMPILER_CHECK(IOC_DIR(0x12345678) == _IOC_DIR(0x12345678)); COMPILER_CHECK(IOC_NR(0x12345678) == _IOC_NR(0x12345678)); COMPILER_CHECK(IOC_TYPE(0x12345678) == _IOC_TYPE(0x12345678)); #endif // SANITIZER_LINUX #if SANITIZER_LINUX || SANITIZER_FREEBSD // There are more undocumented fields in dl_phdr_info that we are not interested // in. COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info)); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); #endif // SANITIZER_LINUX || SANITIZER_FREEBSD #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID CHECK_TYPE_SIZE(glob_t); CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc); CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv); CHECK_SIZE_AND_OFFSET(glob_t, gl_offs); CHECK_SIZE_AND_OFFSET(glob_t, gl_flags); CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir); CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir); CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir); CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat); CHECK_SIZE_AND_OFFSET(glob_t, gl_stat); #endif CHECK_TYPE_SIZE(addrinfo); CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags); CHECK_SIZE_AND_OFFSET(addrinfo, ai_family); CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype); CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol); CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen); CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname); CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr); CHECK_TYPE_SIZE(hostent); CHECK_SIZE_AND_OFFSET(hostent, h_name); CHECK_SIZE_AND_OFFSET(hostent, h_aliases); CHECK_SIZE_AND_OFFSET(hostent, h_addrtype); CHECK_SIZE_AND_OFFSET(hostent, h_length); CHECK_SIZE_AND_OFFSET(hostent, h_addr_list); CHECK_TYPE_SIZE(iovec); CHECK_SIZE_AND_OFFSET(iovec, iov_base); CHECK_SIZE_AND_OFFSET(iovec, iov_len); CHECK_TYPE_SIZE(msghdr); CHECK_SIZE_AND_OFFSET(msghdr, msg_name); CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen); CHECK_SIZE_AND_OFFSET(msghdr, msg_iov); CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen); CHECK_SIZE_AND_OFFSET(msghdr, msg_control); CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen); CHECK_SIZE_AND_OFFSET(msghdr, msg_flags); CHECK_TYPE_SIZE(cmsghdr); CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len); CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level); CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type); COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); CHECK_SIZE_AND_OFFSET(dirent, d_ino); #if SANITIZER_MAC CHECK_SIZE_AND_OFFSET(dirent, d_seekoff); #elif SANITIZER_FREEBSD // There is no 'd_off' field on FreeBSD. #else CHECK_SIZE_AND_OFFSET(dirent, d_off); #endif CHECK_SIZE_AND_OFFSET(dirent, d_reclen); #if SANITIZER_LINUX && !SANITIZER_ANDROID COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64)); CHECK_SIZE_AND_OFFSET(dirent64, d_ino); CHECK_SIZE_AND_OFFSET(dirent64, d_off); CHECK_SIZE_AND_OFFSET(dirent64, d_reclen); #endif CHECK_TYPE_SIZE(ifconf); CHECK_SIZE_AND_OFFSET(ifconf, ifc_len); CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu); CHECK_TYPE_SIZE(pollfd); CHECK_SIZE_AND_OFFSET(pollfd, fd); CHECK_SIZE_AND_OFFSET(pollfd, events); CHECK_SIZE_AND_OFFSET(pollfd, revents); CHECK_TYPE_SIZE(nfds_t); CHECK_TYPE_SIZE(sigset_t); COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); // Can't write checks for sa_handler and sa_sigaction due to them being // preprocessor macros. CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask); CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags); #if SANITIZER_LINUX CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer); #endif #if SANITIZER_LINUX CHECK_TYPE_SIZE(__sysctl_args); CHECK_SIZE_AND_OFFSET(__sysctl_args, name); CHECK_SIZE_AND_OFFSET(__sysctl_args, nlen); CHECK_SIZE_AND_OFFSET(__sysctl_args, oldval); CHECK_SIZE_AND_OFFSET(__sysctl_args, oldlenp); CHECK_SIZE_AND_OFFSET(__sysctl_args, newval); CHECK_SIZE_AND_OFFSET(__sysctl_args, newlen); CHECK_TYPE_SIZE(__kernel_uid_t); CHECK_TYPE_SIZE(__kernel_gid_t); #if !defined(__aarch64__) CHECK_TYPE_SIZE(__kernel_old_uid_t); CHECK_TYPE_SIZE(__kernel_old_gid_t); #endif CHECK_TYPE_SIZE(__kernel_off_t); CHECK_TYPE_SIZE(__kernel_loff_t); CHECK_TYPE_SIZE(__kernel_fd_set); #endif #if !SANITIZER_ANDROID CHECK_TYPE_SIZE(wordexp_t); CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc); CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv); CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs); #endif CHECK_TYPE_SIZE(tm); CHECK_SIZE_AND_OFFSET(tm, tm_sec); CHECK_SIZE_AND_OFFSET(tm, tm_min); CHECK_SIZE_AND_OFFSET(tm, tm_hour); CHECK_SIZE_AND_OFFSET(tm, tm_mday); CHECK_SIZE_AND_OFFSET(tm, tm_mon); CHECK_SIZE_AND_OFFSET(tm, tm_year); CHECK_SIZE_AND_OFFSET(tm, tm_wday); CHECK_SIZE_AND_OFFSET(tm, tm_yday); CHECK_SIZE_AND_OFFSET(tm, tm_isdst); CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff); CHECK_SIZE_AND_OFFSET(tm, tm_zone); #if SANITIZER_LINUX CHECK_TYPE_SIZE(mntent); CHECK_SIZE_AND_OFFSET(mntent, mnt_fsname); CHECK_SIZE_AND_OFFSET(mntent, mnt_dir); CHECK_SIZE_AND_OFFSET(mntent, mnt_type); CHECK_SIZE_AND_OFFSET(mntent, mnt_opts); CHECK_SIZE_AND_OFFSET(mntent, mnt_freq); CHECK_SIZE_AND_OFFSET(mntent, mnt_passno); #endif CHECK_TYPE_SIZE(ether_addr); #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID CHECK_TYPE_SIZE(ipc_perm); # if SANITIZER_FREEBSD CHECK_SIZE_AND_OFFSET(ipc_perm, key); CHECK_SIZE_AND_OFFSET(ipc_perm, seq); # else CHECK_SIZE_AND_OFFSET(ipc_perm, __key); CHECK_SIZE_AND_OFFSET(ipc_perm, __seq); # endif CHECK_SIZE_AND_OFFSET(ipc_perm, uid); CHECK_SIZE_AND_OFFSET(ipc_perm, gid); CHECK_SIZE_AND_OFFSET(ipc_perm, cuid); CHECK_SIZE_AND_OFFSET(ipc_perm, cgid); #ifndef __GLIBC_PREREQ #define __GLIBC_PREREQ(x, y) 0 #endif #if !defined(__aarch64__) || !SANITIZER_LINUX || __GLIBC_PREREQ (2, 21) /* On aarch64 glibc 2.20 and earlier provided incorrect mode field. */ CHECK_SIZE_AND_OFFSET(ipc_perm, mode); #endif CHECK_TYPE_SIZE(shmid_ds); CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm); CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz); CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime); CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime); CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime); CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid); CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid); CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); #endif CHECK_TYPE_SIZE(clock_t); #if SANITIZER_LINUX CHECK_TYPE_SIZE(clockid_t); #endif #if !SANITIZER_ANDROID CHECK_TYPE_SIZE(ifaddrs); CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr); CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); #if SANITIZER_LINUX || SANITIZER_FREEBSD // Compare against the union, because we can't reach into the union in a // compliant way. #ifdef ifa_dstaddr #undef ifa_dstaddr #endif # if SANITIZER_FREEBSD CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); # else COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)NULL)->ifa_dstaddr) == sizeof(((ifaddrs *)NULL)->ifa_ifu)); COMPILER_CHECK(offsetof(__sanitizer_ifaddrs, ifa_dstaddr) == offsetof(ifaddrs, ifa_ifu)); # endif // SANITIZER_FREEBSD #else CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); #endif // SANITIZER_LINUX CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); #endif #if SANITIZER_LINUX COMPILER_CHECK(sizeof(__sanitizer_mallinfo) == sizeof(struct mallinfo)); #endif #if !SANITIZER_ANDROID CHECK_TYPE_SIZE(timeb); CHECK_SIZE_AND_OFFSET(timeb, time); CHECK_SIZE_AND_OFFSET(timeb, millitm); CHECK_SIZE_AND_OFFSET(timeb, timezone); CHECK_SIZE_AND_OFFSET(timeb, dstflag); #endif CHECK_TYPE_SIZE(passwd); CHECK_SIZE_AND_OFFSET(passwd, pw_name); CHECK_SIZE_AND_OFFSET(passwd, pw_passwd); CHECK_SIZE_AND_OFFSET(passwd, pw_uid); CHECK_SIZE_AND_OFFSET(passwd, pw_gid); CHECK_SIZE_AND_OFFSET(passwd, pw_dir); CHECK_SIZE_AND_OFFSET(passwd, pw_shell); #if !SANITIZER_ANDROID CHECK_SIZE_AND_OFFSET(passwd, pw_gecos); #endif #if SANITIZER_MAC CHECK_SIZE_AND_OFFSET(passwd, pw_change); CHECK_SIZE_AND_OFFSET(passwd, pw_expire); CHECK_SIZE_AND_OFFSET(passwd, pw_class); #endif CHECK_TYPE_SIZE(group); CHECK_SIZE_AND_OFFSET(group, gr_name); CHECK_SIZE_AND_OFFSET(group, gr_passwd); CHECK_SIZE_AND_OFFSET(group, gr_gid); CHECK_SIZE_AND_OFFSET(group, gr_mem); #if SANITIZER_LINUX && !SANITIZER_ANDROID CHECK_TYPE_SIZE(XDR); CHECK_SIZE_AND_OFFSET(XDR, x_op); CHECK_SIZE_AND_OFFSET(XDR, x_ops); CHECK_SIZE_AND_OFFSET(XDR, x_public); CHECK_SIZE_AND_OFFSET(XDR, x_private); CHECK_SIZE_AND_OFFSET(XDR, x_base); CHECK_SIZE_AND_OFFSET(XDR, x_handy); COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE); COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE)); CHECK_SIZE_AND_OFFSET(FILE, _flags); CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr); CHECK_SIZE_AND_OFFSET(FILE, _IO_read_end); CHECK_SIZE_AND_OFFSET(FILE, _IO_read_base); CHECK_SIZE_AND_OFFSET(FILE, _IO_write_ptr); CHECK_SIZE_AND_OFFSET(FILE, _IO_write_end); CHECK_SIZE_AND_OFFSET(FILE, _IO_write_base); CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_base); CHECK_SIZE_AND_OFFSET(FILE, _IO_buf_end); CHECK_SIZE_AND_OFFSET(FILE, _IO_save_base); CHECK_SIZE_AND_OFFSET(FILE, _IO_backup_base); CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end); CHECK_SIZE_AND_OFFSET(FILE, _markers); CHECK_SIZE_AND_OFFSET(FILE, _chain); CHECK_SIZE_AND_OFFSET(FILE, _fileno); #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk)); CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit); CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev); CHECK_TYPE_SIZE(obstack); CHECK_SIZE_AND_OFFSET(obstack, chunk_size); CHECK_SIZE_AND_OFFSET(obstack, chunk); CHECK_SIZE_AND_OFFSET(obstack, object_base); CHECK_SIZE_AND_OFFSET(obstack, next_free); #endif #endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h (revision 279194) @@ -1,1312 +1,1316 @@ //===-- sanitizer_platform_limits_posix.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 Sanitizer common code. // // Sizes and layouts of platform-specific POSIX data structures. //===----------------------------------------------------------------------===// #ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H #define SANITIZER_PLATFORM_LIMITS_POSIX_H #include "sanitizer_internal_defs.h" #include "sanitizer_platform.h" #if SANITIZER_FREEBSD // FreeBSD's dlopen() returns a pointer to an Obj_Entry structure that // incroporates the map structure. # define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 544))) #else # define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) ((link_map*)(handle)) #endif // !SANITIZER_FREEBSD namespace __sanitizer { extern unsigned struct_utsname_sz; extern unsigned struct_stat_sz; #if !SANITIZER_FREEBSD && !SANITIZER_IOS extern unsigned struct_stat64_sz; #endif extern unsigned struct_rusage_sz; extern unsigned siginfo_t_sz; extern unsigned struct_itimerval_sz; extern unsigned pthread_t_sz; extern unsigned pthread_cond_t_sz; extern unsigned pid_t_sz; extern unsigned timeval_sz; extern unsigned uid_t_sz; extern unsigned gid_t_sz; extern unsigned mbstate_t_sz; extern unsigned struct_timezone_sz; extern unsigned struct_tms_sz; extern unsigned struct_itimerspec_sz; extern unsigned struct_sigevent_sz; extern unsigned struct_sched_param_sz; extern unsigned struct_statfs64_sz; #if !SANITIZER_ANDROID extern unsigned struct_statfs_sz; extern unsigned struct_sockaddr_sz; extern unsigned ucontext_t_sz; #endif // !SANITIZER_ANDROID #if SANITIZER_LINUX #if defined(__x86_64__) const unsigned struct_kernel_stat_sz = 144; const unsigned struct_kernel_stat64_sz = 0; #elif defined(__i386__) const unsigned struct_kernel_stat_sz = 64; const unsigned struct_kernel_stat64_sz = 96; #elif defined(__arm__) const unsigned struct_kernel_stat_sz = 64; const unsigned struct_kernel_stat64_sz = 104; #elif defined(__aarch64__) const unsigned struct_kernel_stat_sz = 128; const unsigned struct_kernel_stat64_sz = 104; #elif defined(__powerpc__) && !defined(__powerpc64__) const unsigned struct_kernel_stat_sz = 72; const unsigned struct_kernel_stat64_sz = 104; #elif defined(__powerpc64__) const unsigned struct_kernel_stat_sz = 144; const unsigned struct_kernel_stat64_sz = 104; #elif defined(__mips__) #if SANITIZER_WORDSIZE == 64 const unsigned struct_kernel_stat_sz = 216; #else const unsigned struct_kernel_stat_sz = 144; #endif const unsigned struct_kernel_stat64_sz = 104; #endif struct __sanitizer_perf_event_attr { unsigned type; unsigned size; // More fields that vary with the kernel version. }; extern unsigned struct_epoll_event_sz; extern unsigned struct_sysinfo_sz; extern unsigned __user_cap_header_struct_sz; extern unsigned __user_cap_data_struct_sz; extern unsigned struct_new_utsname_sz; extern unsigned struct_old_utsname_sz; extern unsigned struct_oldold_utsname_sz; const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long); #endif // SANITIZER_LINUX #if SANITIZER_LINUX || SANITIZER_FREEBSD #if defined(__powerpc64__) const unsigned struct___old_kernel_stat_sz = 0; #else const unsigned struct___old_kernel_stat_sz = 32; #endif extern unsigned struct_rlimit_sz; extern unsigned struct_utimbuf_sz; extern unsigned struct_timespec_sz; struct __sanitizer_iocb { u64 aio_data; u32 aio_key_or_aio_reserved1; // Simply crazy. u32 aio_reserved1_or_aio_key; // Luckily, we don't need these. u16 aio_lio_opcode; s16 aio_reqprio; u32 aio_fildes; u64 aio_buf; u64 aio_nbytes; s64 aio_offset; u64 aio_reserved2; u64 aio_reserved3; }; struct __sanitizer_io_event { u64 data; u64 obj; u64 res; u64 res2; }; const unsigned iocb_cmd_pread = 0; const unsigned iocb_cmd_pwrite = 1; const unsigned iocb_cmd_preadv = 7; const unsigned iocb_cmd_pwritev = 8; struct __sanitizer___sysctl_args { int *name; int nlen; void *oldval; uptr *oldlenp; void *newval; uptr newlen; unsigned long ___unused[4]; }; const unsigned old_sigset_t_sz = sizeof(unsigned long); #endif // SANITIZER_LINUX || SANITIZER_FREEBSD #if SANITIZER_ANDROID struct __sanitizer_mallinfo { uptr v[10]; }; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID struct __sanitizer_mallinfo { int v[10]; }; extern unsigned struct_ustat_sz; extern unsigned struct_rlimit64_sz; extern unsigned struct_statvfs64_sz; struct __sanitizer_ipc_perm { int __key; int uid; int gid; int cuid; int cgid; #ifdef __powerpc__ unsigned mode; unsigned __seq; u64 __unused1; u64 __unused2; #elif defined(__mips__) || defined(__aarch64__) unsigned int mode; unsigned short __seq; unsigned short __pad1; unsigned long __unused1; unsigned long __unused2; #else unsigned short mode; unsigned short __pad1; unsigned short __seq; unsigned short __pad2; #if defined(__x86_64__) && !defined(_LP64) u64 __unused1; u64 __unused2; #else unsigned long __unused1; unsigned long __unused2; #endif #endif }; struct __sanitizer_shmid_ds { __sanitizer_ipc_perm shm_perm; #ifndef __powerpc__ uptr shm_segsz; #elif !defined(__powerpc64__) uptr __unused0; #endif #if defined(__x86_64__) && !defined(_LP64) u64 shm_atime; u64 shm_dtime; u64 shm_ctime; #else uptr shm_atime; #if !defined(_LP64) && !defined(__mips__) uptr __unused1; #endif uptr shm_dtime; #if !defined(_LP64) && !defined(__mips__) uptr __unused2; #endif uptr shm_ctime; #if !defined(_LP64) && !defined(__mips__) uptr __unused3; #endif #endif #ifdef __powerpc__ uptr shm_segsz; #endif int shm_cpid; int shm_lpid; #if defined(__x86_64__) && !defined(_LP64) u64 shm_nattch; u64 __unused4; u64 __unused5; #else uptr shm_nattch; uptr __unused4; uptr __unused5; #endif }; #elif SANITIZER_FREEBSD struct __sanitizer_ipc_perm { unsigned int cuid; unsigned int cgid; unsigned int uid; unsigned int gid; unsigned short mode; unsigned short seq; long key; }; struct __sanitizer_shmid_ds { __sanitizer_ipc_perm shm_perm; unsigned long shm_segsz; unsigned int shm_lpid; unsigned int shm_cpid; int shm_nattch; unsigned long shm_atime; unsigned long shm_dtime; unsigned long shm_ctime; }; #endif #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID extern unsigned struct_msqid_ds_sz; extern unsigned struct_mq_attr_sz; extern unsigned struct_timex_sz; extern unsigned struct_statvfs_sz; #endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID struct __sanitizer_iovec { void *iov_base; uptr iov_len; }; #if !SANITIZER_ANDROID struct __sanitizer_ifaddrs { struct __sanitizer_ifaddrs *ifa_next; char *ifa_name; unsigned int ifa_flags; void *ifa_addr; // (struct sockaddr *) void *ifa_netmask; // (struct sockaddr *) // This is a union on Linux. # ifdef ifa_dstaddr # undef ifa_dstaddr # endif void *ifa_dstaddr; // (struct sockaddr *) void *ifa_data; }; #endif // !SANITIZER_ANDROID #if SANITIZER_MAC typedef unsigned long __sanitizer_pthread_key_t; #else typedef unsigned __sanitizer_pthread_key_t; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID struct __sanitizer_XDR { int x_op; void *x_ops; uptr x_public; uptr x_private; uptr x_base; unsigned x_handy; }; const int __sanitizer_XDR_ENCODE = 0; const int __sanitizer_XDR_DECODE = 1; const int __sanitizer_XDR_FREE = 2; #endif struct __sanitizer_passwd { char *pw_name; char *pw_passwd; int pw_uid; int pw_gid; #if SANITIZER_MAC || SANITIZER_FREEBSD long pw_change; char *pw_class; #endif #if !SANITIZER_ANDROID char *pw_gecos; #endif char *pw_dir; char *pw_shell; #if SANITIZER_MAC || SANITIZER_FREEBSD long pw_expire; #endif #if SANITIZER_FREEBSD int pw_fields; #endif }; struct __sanitizer_group { char *gr_name; char *gr_passwd; int gr_gid; char **gr_mem; }; #if defined(__x86_64__) && !defined(_LP64) typedef long long __sanitizer_time_t; #else typedef long __sanitizer_time_t; #endif struct __sanitizer_timeb { __sanitizer_time_t time; unsigned short millitm; short timezone; short dstflag; }; struct __sanitizer_ether_addr { u8 octet[6]; }; struct __sanitizer_tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; long int tm_gmtoff; const char *tm_zone; }; #if SANITIZER_LINUX struct __sanitizer_mntent { char *mnt_fsname; char *mnt_dir; char *mnt_type; char *mnt_opts; int mnt_freq; int mnt_passno; }; #endif #if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD struct __sanitizer_msghdr { void *msg_name; unsigned msg_namelen; struct __sanitizer_iovec *msg_iov; unsigned msg_iovlen; void *msg_control; unsigned msg_controllen; int msg_flags; }; struct __sanitizer_cmsghdr { unsigned cmsg_len; int cmsg_level; int cmsg_type; }; #else struct __sanitizer_msghdr { void *msg_name; unsigned msg_namelen; struct __sanitizer_iovec *msg_iov; uptr msg_iovlen; void *msg_control; uptr msg_controllen; int msg_flags; }; struct __sanitizer_cmsghdr { uptr cmsg_len; int cmsg_level; int cmsg_type; }; #endif #if SANITIZER_MAC struct __sanitizer_dirent { unsigned long long d_ino; unsigned long long d_seekoff; unsigned short d_reclen; // more fields that we don't care about }; #elif SANITIZER_FREEBSD struct __sanitizer_dirent { unsigned int d_fileno; unsigned short d_reclen; // more fields that we don't care about }; #elif SANITIZER_ANDROID || defined(__x86_64__) struct __sanitizer_dirent { unsigned long long d_ino; unsigned long long d_off; unsigned short d_reclen; // more fields that we don't care about }; #else struct __sanitizer_dirent { uptr d_ino; uptr d_off; unsigned short d_reclen; // more fields that we don't care about }; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID struct __sanitizer_dirent64 { unsigned long long d_ino; unsigned long long d_off; unsigned short d_reclen; // more fields that we don't care about }; #endif // 'clock_t' is 32 bits wide on x64 FreeBSD #if SANITIZER_FREEBSD typedef int __sanitizer_clock_t; #elif defined(__x86_64__) && !defined(_LP64) typedef long long __sanitizer_clock_t; #else typedef long __sanitizer_clock_t; #endif #if SANITIZER_LINUX typedef int __sanitizer_clockid_t; #endif #if SANITIZER_LINUX || SANITIZER_FREEBSD #if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)\ || defined(__mips__) typedef unsigned __sanitizer___kernel_uid_t; typedef unsigned __sanitizer___kernel_gid_t; #else typedef unsigned short __sanitizer___kernel_uid_t; typedef unsigned short __sanitizer___kernel_gid_t; #endif #if defined(__x86_64__) && !defined(_LP64) typedef long long __sanitizer___kernel_off_t; #else typedef long __sanitizer___kernel_off_t; #endif #if defined(__powerpc__) || defined(__mips__) typedef unsigned int __sanitizer___kernel_old_uid_t; typedef unsigned int __sanitizer___kernel_old_gid_t; #else typedef unsigned short __sanitizer___kernel_old_uid_t; typedef unsigned short __sanitizer___kernel_old_gid_t; #endif typedef long long __sanitizer___kernel_loff_t; typedef struct { unsigned long fds_bits[1024 / (8 * sizeof(long))]; } __sanitizer___kernel_fd_set; #endif // This thing depends on the platform. We are only interested in the upper // limit. Verified with a compiler assert in .cc. const int pthread_attr_t_max_sz = 128; union __sanitizer_pthread_attr_t { char size[pthread_attr_t_max_sz]; // NOLINT void *align; }; #if SANITIZER_ANDROID typedef unsigned long __sanitizer_sigset_t; #elif SANITIZER_MAC typedef unsigned __sanitizer_sigset_t; #elif SANITIZER_LINUX struct __sanitizer_sigset_t { // The size is determined by looking at sizeof of real sigset_t on linux. uptr val[128 / sizeof(uptr)]; }; #elif SANITIZER_FREEBSD struct __sanitizer_sigset_t { // uint32_t * 4 unsigned int __bits[4]; }; #endif // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. struct __sanitizer_sigaction { #if defined(__mips__) && !SANITIZER_FREEBSD unsigned int sa_flags; #endif union { void (*sigaction)(int sig, void *siginfo, void *uctx); void (*handler)(int sig); }; #if SANITIZER_FREEBSD int sa_flags; __sanitizer_sigset_t sa_mask; #else __sanitizer_sigset_t sa_mask; #ifndef __mips__ int sa_flags; #endif #endif #if SANITIZER_LINUX void (*sa_restorer)(); #endif #if defined(__mips__) && (SANITIZER_WORDSIZE == 32) int sa_resv[1]; #endif }; #if SANITIZER_FREEBSD typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t; +#elif defined(__mips__) + struct __sanitizer_kernel_sigset_t { + u8 sig[16]; + }; #else struct __sanitizer_kernel_sigset_t { u8 sig[8]; }; #endif // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. struct __sanitizer_kernel_sigaction_t { union { void (*handler)(int signo); void (*sigaction)(int signo, void *info, void *ctx); }; unsigned long sa_flags; void (*sa_restorer)(void); __sanitizer_kernel_sigset_t sa_mask; }; extern uptr sig_ign; extern uptr sig_dfl; extern uptr sa_siginfo; #if SANITIZER_LINUX extern int e_tabsz; #endif extern int af_inet; extern int af_inet6; uptr __sanitizer_in_addr_sz(int af); #if SANITIZER_LINUX || SANITIZER_FREEBSD struct __sanitizer_dl_phdr_info { uptr dlpi_addr; const char *dlpi_name; const void *dlpi_phdr; short dlpi_phnum; }; #endif struct __sanitizer_addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; #if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD unsigned ai_addrlen; char *ai_canonname; void *ai_addr; #else // LINUX unsigned ai_addrlen; void *ai_addr; char *ai_canonname; #endif struct __sanitizer_addrinfo *ai_next; }; struct __sanitizer_hostent { char *h_name; char **h_aliases; int h_addrtype; int h_length; char **h_addr_list; }; struct __sanitizer_pollfd { int fd; short events; short revents; }; #if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD typedef unsigned __sanitizer_nfds_t; #else typedef unsigned long __sanitizer_nfds_t; #endif #if !SANITIZER_ANDROID # if SANITIZER_LINUX struct __sanitizer_glob_t { uptr gl_pathc; char **gl_pathv; uptr gl_offs; int gl_flags; void (*gl_closedir)(void *dirp); void *(*gl_readdir)(void *dirp); void *(*gl_opendir)(const char *); int (*gl_lstat)(const char *, void *); int (*gl_stat)(const char *, void *); }; # elif SANITIZER_FREEBSD struct __sanitizer_glob_t { uptr gl_pathc; uptr gl_matchc; uptr gl_offs; int gl_flags; char **gl_pathv; int (*gl_errfunc)(const char*, int); void (*gl_closedir)(void *dirp); struct dirent *(*gl_readdir)(void *dirp); void *(*gl_opendir)(const char*); int (*gl_lstat)(const char*, void* /* struct stat* */); int (*gl_stat)(const char*, void* /* struct stat* */); }; # endif // SANITIZER_FREEBSD # if SANITIZER_LINUX || SANITIZER_FREEBSD extern int glob_nomatch; extern int glob_altdirfunc; # endif #endif // !SANITIZER_ANDROID extern unsigned path_max; struct __sanitizer_wordexp_t { uptr we_wordc; char **we_wordv; uptr we_offs; #if SANITIZER_FREEBSD char *we_strings; uptr we_nbytes; #endif }; #if SANITIZER_LINUX && !SANITIZER_ANDROID struct __sanitizer_FILE { int _flags; char *_IO_read_ptr; char *_IO_read_end; char *_IO_read_base; char *_IO_write_base; char *_IO_write_ptr; char *_IO_write_end; char *_IO_buf_base; char *_IO_buf_end; char *_IO_save_base; char *_IO_backup_base; char *_IO_save_end; void *_markers; __sanitizer_FILE *_chain; int _fileno; }; # define SANITIZER_HAS_STRUCT_FILE 1 #else typedef void __sanitizer_FILE; # define SANITIZER_HAS_STRUCT_FILE 0 #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID && \ - (defined(__i386) || defined(__x86_64)) + (defined(__i386) || defined(__x86_64) || defined(__mips64)) extern unsigned struct_user_regs_struct_sz; extern unsigned struct_user_fpregs_struct_sz; extern unsigned struct_user_fpxregs_struct_sz; extern int ptrace_peektext; extern int ptrace_peekdata; extern int ptrace_peekuser; extern int ptrace_getregs; extern int ptrace_setregs; extern int ptrace_getfpregs; extern int ptrace_setfpregs; extern int ptrace_getfpxregs; extern int ptrace_setfpxregs; extern int ptrace_getsiginfo; extern int ptrace_setsiginfo; extern int ptrace_getregset; extern int ptrace_setregset; extern int ptrace_geteventmsg; #endif #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID extern unsigned struct_shminfo_sz; extern unsigned struct_shm_info_sz; extern int shmctl_ipc_stat; extern int shmctl_ipc_info; extern int shmctl_shm_info; extern int shmctl_shm_stat; #endif extern int map_fixed; // ioctl arguments struct __sanitizer_ifconf { int ifc_len; union { void *ifcu_req; } ifc_ifcu; #if SANITIZER_MAC } __attribute__((packed)); #else }; #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID struct __sanitizer__obstack_chunk { char *limit; struct __sanitizer__obstack_chunk *prev; }; struct __sanitizer_obstack { long chunk_size; struct __sanitizer__obstack_chunk *chunk; char *object_base; char *next_free; uptr more_fields[7]; }; #endif #define IOC_NRBITS 8 #define IOC_TYPEBITS 8 #if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__) #define IOC_SIZEBITS 13 #define IOC_DIRBITS 3 #define IOC_NONE 1U #define IOC_WRITE 4U #define IOC_READ 2U #else #define IOC_SIZEBITS 14 #define IOC_DIRBITS 2 #define IOC_NONE 0U #define IOC_WRITE 1U #define IOC_READ 2U #endif #define IOC_NRMASK ((1 << IOC_NRBITS) - 1) #define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1) #define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1) #if defined(IOC_DIRMASK) #undef IOC_DIRMASK #endif #define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1) #define IOC_NRSHIFT 0 #define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS) #define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS) #define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS) #define EVIOC_EV_MAX 0x1f #define EVIOC_ABS_MAX 0x3f #define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK) #define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK) #define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) #define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) extern unsigned struct_arpreq_sz; extern unsigned struct_ifreq_sz; extern unsigned struct_termios_sz; extern unsigned struct_winsize_sz; #if SANITIZER_LINUX extern unsigned struct_cdrom_msf_sz; extern unsigned struct_cdrom_multisession_sz; extern unsigned struct_cdrom_read_audio_sz; extern unsigned struct_cdrom_subchnl_sz; extern unsigned struct_cdrom_ti_sz; extern unsigned struct_cdrom_tocentry_sz; extern unsigned struct_cdrom_tochdr_sz; extern unsigned struct_cdrom_volctrl_sz; extern unsigned struct_ff_effect_sz; extern unsigned struct_floppy_drive_params_sz; extern unsigned struct_floppy_drive_struct_sz; extern unsigned struct_floppy_fdc_state_sz; extern unsigned struct_floppy_max_errors_sz; extern unsigned struct_floppy_raw_cmd_sz; extern unsigned struct_floppy_struct_sz; extern unsigned struct_floppy_write_errors_sz; extern unsigned struct_format_descr_sz; extern unsigned struct_hd_driveid_sz; extern unsigned struct_hd_geometry_sz; extern unsigned struct_input_absinfo_sz; extern unsigned struct_input_id_sz; extern unsigned struct_mtpos_sz; extern unsigned struct_termio_sz; extern unsigned struct_vt_consize_sz; extern unsigned struct_vt_sizes_sz; extern unsigned struct_vt_stat_sz; #endif // SANITIZER_LINUX #if SANITIZER_LINUX || SANITIZER_FREEBSD extern unsigned struct_copr_buffer_sz; extern unsigned struct_copr_debug_buf_sz; extern unsigned struct_copr_msg_sz; extern unsigned struct_midi_info_sz; extern unsigned struct_mtget_sz; extern unsigned struct_mtop_sz; extern unsigned struct_rtentry_sz; extern unsigned struct_sbi_instrument_sz; extern unsigned struct_seq_event_rec_sz; extern unsigned struct_synth_info_sz; extern unsigned struct_vt_mode_sz; #endif // SANITIZER_LINUX || SANITIZER_FREEBSD #if SANITIZER_LINUX && !SANITIZER_ANDROID extern unsigned struct_ax25_parms_struct_sz; extern unsigned struct_cyclades_monitor_sz; extern unsigned struct_input_keymap_entry_sz; extern unsigned struct_ipx_config_data_sz; extern unsigned struct_kbdiacrs_sz; extern unsigned struct_kbentry_sz; extern unsigned struct_kbkeycode_sz; extern unsigned struct_kbsentry_sz; extern unsigned struct_mtconfiginfo_sz; extern unsigned struct_nr_parms_struct_sz; extern unsigned struct_scc_modem_sz; extern unsigned struct_scc_stat_sz; extern unsigned struct_serial_multiport_struct_sz; extern unsigned struct_serial_struct_sz; extern unsigned struct_sockaddr_ax25_sz; extern unsigned struct_unimapdesc_sz; extern unsigned struct_unimapinit_sz; #endif // SANITIZER_LINUX && !SANITIZER_ANDROID #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID extern unsigned struct_audio_buf_info_sz; extern unsigned struct_ppp_stats_sz; #endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID #if !SANITIZER_ANDROID && !SANITIZER_MAC extern unsigned struct_sioc_sg_req_sz; extern unsigned struct_sioc_vif_req_sz; #endif // ioctl request identifiers // A special value to mark ioctls that are not present on the target platform, // when it can not be determined without including any system headers. extern const unsigned IOCTL_NOT_PRESENT; extern unsigned IOCTL_FIOASYNC; extern unsigned IOCTL_FIOCLEX; extern unsigned IOCTL_FIOGETOWN; extern unsigned IOCTL_FIONBIO; extern unsigned IOCTL_FIONCLEX; extern unsigned IOCTL_FIOSETOWN; extern unsigned IOCTL_SIOCADDMULTI; extern unsigned IOCTL_SIOCATMARK; extern unsigned IOCTL_SIOCDELMULTI; extern unsigned IOCTL_SIOCGIFADDR; extern unsigned IOCTL_SIOCGIFBRDADDR; extern unsigned IOCTL_SIOCGIFCONF; extern unsigned IOCTL_SIOCGIFDSTADDR; extern unsigned IOCTL_SIOCGIFFLAGS; extern unsigned IOCTL_SIOCGIFMETRIC; extern unsigned IOCTL_SIOCGIFMTU; extern unsigned IOCTL_SIOCGIFNETMASK; extern unsigned IOCTL_SIOCGPGRP; extern unsigned IOCTL_SIOCSIFADDR; extern unsigned IOCTL_SIOCSIFBRDADDR; extern unsigned IOCTL_SIOCSIFDSTADDR; extern unsigned IOCTL_SIOCSIFFLAGS; extern unsigned IOCTL_SIOCSIFMETRIC; extern unsigned IOCTL_SIOCSIFMTU; extern unsigned IOCTL_SIOCSIFNETMASK; extern unsigned IOCTL_SIOCSPGRP; extern unsigned IOCTL_TIOCCONS; extern unsigned IOCTL_TIOCEXCL; extern unsigned IOCTL_TIOCGETD; extern unsigned IOCTL_TIOCGPGRP; extern unsigned IOCTL_TIOCGWINSZ; extern unsigned IOCTL_TIOCMBIC; extern unsigned IOCTL_TIOCMBIS; extern unsigned IOCTL_TIOCMGET; extern unsigned IOCTL_TIOCMSET; extern unsigned IOCTL_TIOCNOTTY; extern unsigned IOCTL_TIOCNXCL; extern unsigned IOCTL_TIOCOUTQ; extern unsigned IOCTL_TIOCPKT; extern unsigned IOCTL_TIOCSCTTY; extern unsigned IOCTL_TIOCSETD; extern unsigned IOCTL_TIOCSPGRP; extern unsigned IOCTL_TIOCSTI; extern unsigned IOCTL_TIOCSWINSZ; #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID extern unsigned IOCTL_SIOCGETSGCNT; extern unsigned IOCTL_SIOCGETVIFCNT; #endif #if SANITIZER_LINUX extern unsigned IOCTL_EVIOCGABS; extern unsigned IOCTL_EVIOCGBIT; extern unsigned IOCTL_EVIOCGEFFECTS; extern unsigned IOCTL_EVIOCGID; extern unsigned IOCTL_EVIOCGKEY; extern unsigned IOCTL_EVIOCGKEYCODE; extern unsigned IOCTL_EVIOCGLED; extern unsigned IOCTL_EVIOCGNAME; extern unsigned IOCTL_EVIOCGPHYS; extern unsigned IOCTL_EVIOCGRAB; extern unsigned IOCTL_EVIOCGREP; extern unsigned IOCTL_EVIOCGSND; extern unsigned IOCTL_EVIOCGSW; extern unsigned IOCTL_EVIOCGUNIQ; extern unsigned IOCTL_EVIOCGVERSION; extern unsigned IOCTL_EVIOCRMFF; extern unsigned IOCTL_EVIOCSABS; extern unsigned IOCTL_EVIOCSFF; extern unsigned IOCTL_EVIOCSKEYCODE; extern unsigned IOCTL_EVIOCSREP; extern unsigned IOCTL_BLKFLSBUF; extern unsigned IOCTL_BLKGETSIZE; extern unsigned IOCTL_BLKRAGET; extern unsigned IOCTL_BLKRASET; extern unsigned IOCTL_BLKROGET; extern unsigned IOCTL_BLKROSET; extern unsigned IOCTL_BLKRRPART; extern unsigned IOCTL_CDROMAUDIOBUFSIZ; extern unsigned IOCTL_CDROMEJECT; extern unsigned IOCTL_CDROMEJECT_SW; extern unsigned IOCTL_CDROMMULTISESSION; extern unsigned IOCTL_CDROMPAUSE; extern unsigned IOCTL_CDROMPLAYMSF; extern unsigned IOCTL_CDROMPLAYTRKIND; extern unsigned IOCTL_CDROMREADAUDIO; extern unsigned IOCTL_CDROMREADCOOKED; extern unsigned IOCTL_CDROMREADMODE1; extern unsigned IOCTL_CDROMREADMODE2; extern unsigned IOCTL_CDROMREADRAW; extern unsigned IOCTL_CDROMREADTOCENTRY; extern unsigned IOCTL_CDROMREADTOCHDR; extern unsigned IOCTL_CDROMRESET; extern unsigned IOCTL_CDROMRESUME; extern unsigned IOCTL_CDROMSEEK; extern unsigned IOCTL_CDROMSTART; extern unsigned IOCTL_CDROMSTOP; extern unsigned IOCTL_CDROMSUBCHNL; extern unsigned IOCTL_CDROMVOLCTRL; extern unsigned IOCTL_CDROMVOLREAD; extern unsigned IOCTL_CDROM_GET_UPC; extern unsigned IOCTL_FDCLRPRM; extern unsigned IOCTL_FDDEFPRM; extern unsigned IOCTL_FDFLUSH; extern unsigned IOCTL_FDFMTBEG; extern unsigned IOCTL_FDFMTEND; extern unsigned IOCTL_FDFMTTRK; extern unsigned IOCTL_FDGETDRVPRM; extern unsigned IOCTL_FDGETDRVSTAT; extern unsigned IOCTL_FDGETDRVTYP; extern unsigned IOCTL_FDGETFDCSTAT; extern unsigned IOCTL_FDGETMAXERRS; extern unsigned IOCTL_FDGETPRM; extern unsigned IOCTL_FDMSGOFF; extern unsigned IOCTL_FDMSGON; extern unsigned IOCTL_FDPOLLDRVSTAT; extern unsigned IOCTL_FDRAWCMD; extern unsigned IOCTL_FDRESET; extern unsigned IOCTL_FDSETDRVPRM; extern unsigned IOCTL_FDSETEMSGTRESH; extern unsigned IOCTL_FDSETMAXERRS; extern unsigned IOCTL_FDSETPRM; extern unsigned IOCTL_FDTWADDLE; extern unsigned IOCTL_FDWERRORCLR; extern unsigned IOCTL_FDWERRORGET; extern unsigned IOCTL_HDIO_DRIVE_CMD; extern unsigned IOCTL_HDIO_GETGEO; extern unsigned IOCTL_HDIO_GET_32BIT; extern unsigned IOCTL_HDIO_GET_DMA; extern unsigned IOCTL_HDIO_GET_IDENTITY; extern unsigned IOCTL_HDIO_GET_KEEPSETTINGS; extern unsigned IOCTL_HDIO_GET_MULTCOUNT; extern unsigned IOCTL_HDIO_GET_NOWERR; extern unsigned IOCTL_HDIO_GET_UNMASKINTR; extern unsigned IOCTL_HDIO_SET_32BIT; extern unsigned IOCTL_HDIO_SET_DMA; extern unsigned IOCTL_HDIO_SET_KEEPSETTINGS; extern unsigned IOCTL_HDIO_SET_MULTCOUNT; extern unsigned IOCTL_HDIO_SET_NOWERR; extern unsigned IOCTL_HDIO_SET_UNMASKINTR; extern unsigned IOCTL_MTIOCPOS; extern unsigned IOCTL_PPPIOCGASYNCMAP; extern unsigned IOCTL_PPPIOCGDEBUG; extern unsigned IOCTL_PPPIOCGFLAGS; extern unsigned IOCTL_PPPIOCGUNIT; extern unsigned IOCTL_PPPIOCGXASYNCMAP; extern unsigned IOCTL_PPPIOCSASYNCMAP; extern unsigned IOCTL_PPPIOCSDEBUG; extern unsigned IOCTL_PPPIOCSFLAGS; extern unsigned IOCTL_PPPIOCSMAXCID; extern unsigned IOCTL_PPPIOCSMRU; extern unsigned IOCTL_PPPIOCSXASYNCMAP; extern unsigned IOCTL_SIOCDARP; extern unsigned IOCTL_SIOCDRARP; extern unsigned IOCTL_SIOCGARP; extern unsigned IOCTL_SIOCGIFENCAP; extern unsigned IOCTL_SIOCGIFHWADDR; extern unsigned IOCTL_SIOCGIFMAP; extern unsigned IOCTL_SIOCGIFMEM; extern unsigned IOCTL_SIOCGIFNAME; extern unsigned IOCTL_SIOCGIFSLAVE; extern unsigned IOCTL_SIOCGRARP; extern unsigned IOCTL_SIOCGSTAMP; extern unsigned IOCTL_SIOCSARP; extern unsigned IOCTL_SIOCSIFENCAP; extern unsigned IOCTL_SIOCSIFHWADDR; extern unsigned IOCTL_SIOCSIFLINK; extern unsigned IOCTL_SIOCSIFMAP; extern unsigned IOCTL_SIOCSIFMEM; extern unsigned IOCTL_SIOCSIFSLAVE; extern unsigned IOCTL_SIOCSRARP; extern unsigned IOCTL_SNDCTL_COPR_HALT; extern unsigned IOCTL_SNDCTL_COPR_LOAD; extern unsigned IOCTL_SNDCTL_COPR_RCODE; extern unsigned IOCTL_SNDCTL_COPR_RCVMSG; extern unsigned IOCTL_SNDCTL_COPR_RDATA; extern unsigned IOCTL_SNDCTL_COPR_RESET; extern unsigned IOCTL_SNDCTL_COPR_RUN; extern unsigned IOCTL_SNDCTL_COPR_SENDMSG; extern unsigned IOCTL_SNDCTL_COPR_WCODE; extern unsigned IOCTL_SNDCTL_COPR_WDATA; extern unsigned IOCTL_TCFLSH; extern unsigned IOCTL_TCGETA; extern unsigned IOCTL_TCGETS; extern unsigned IOCTL_TCSBRK; extern unsigned IOCTL_TCSBRKP; extern unsigned IOCTL_TCSETA; extern unsigned IOCTL_TCSETAF; extern unsigned IOCTL_TCSETAW; extern unsigned IOCTL_TCSETS; extern unsigned IOCTL_TCSETSF; extern unsigned IOCTL_TCSETSW; extern unsigned IOCTL_TCXONC; extern unsigned IOCTL_TIOCGLCKTRMIOS; extern unsigned IOCTL_TIOCGSOFTCAR; extern unsigned IOCTL_TIOCINQ; extern unsigned IOCTL_TIOCLINUX; extern unsigned IOCTL_TIOCSERCONFIG; extern unsigned IOCTL_TIOCSERGETLSR; extern unsigned IOCTL_TIOCSERGWILD; extern unsigned IOCTL_TIOCSERSWILD; extern unsigned IOCTL_TIOCSLCKTRMIOS; extern unsigned IOCTL_TIOCSSOFTCAR; extern unsigned IOCTL_VT_DISALLOCATE; extern unsigned IOCTL_VT_GETSTATE; extern unsigned IOCTL_VT_RESIZE; extern unsigned IOCTL_VT_RESIZEX; extern unsigned IOCTL_VT_SENDSIG; #endif // SANITIZER_LINUX #if SANITIZER_LINUX || SANITIZER_FREEBSD extern unsigned IOCTL_MTIOCGET; extern unsigned IOCTL_MTIOCTOP; extern unsigned IOCTL_SIOCADDRT; extern unsigned IOCTL_SIOCDELRT; extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE; extern unsigned IOCTL_SNDCTL_DSP_GETFMTS; extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK; extern unsigned IOCTL_SNDCTL_DSP_POST; extern unsigned IOCTL_SNDCTL_DSP_RESET; extern unsigned IOCTL_SNDCTL_DSP_SETFMT; extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT; extern unsigned IOCTL_SNDCTL_DSP_SPEED; extern unsigned IOCTL_SNDCTL_DSP_STEREO; extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE; extern unsigned IOCTL_SNDCTL_DSP_SYNC; extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE; extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR; extern unsigned IOCTL_SNDCTL_MIDI_INFO; extern unsigned IOCTL_SNDCTL_MIDI_PRETIME; extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE; extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT; extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT; extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS; extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS; extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND; extern unsigned IOCTL_SNDCTL_SEQ_PANIC; extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE; extern unsigned IOCTL_SNDCTL_SEQ_RESET; extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES; extern unsigned IOCTL_SNDCTL_SEQ_SYNC; extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI; extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD; extern unsigned IOCTL_SNDCTL_SYNTH_INFO; extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL; extern unsigned IOCTL_SNDCTL_TMR_CONTINUE; extern unsigned IOCTL_SNDCTL_TMR_METRONOME; extern unsigned IOCTL_SNDCTL_TMR_SELECT; extern unsigned IOCTL_SNDCTL_TMR_SOURCE; extern unsigned IOCTL_SNDCTL_TMR_START; extern unsigned IOCTL_SNDCTL_TMR_STOP; extern unsigned IOCTL_SNDCTL_TMR_TEMPO; extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE; extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM; extern unsigned IOCTL_SOUND_MIXER_READ_BASS; extern unsigned IOCTL_SOUND_MIXER_READ_CAPS; extern unsigned IOCTL_SOUND_MIXER_READ_CD; extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK; extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE; extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN; extern unsigned IOCTL_SOUND_MIXER_READ_IMIX; extern unsigned IOCTL_SOUND_MIXER_READ_LINE1; extern unsigned IOCTL_SOUND_MIXER_READ_LINE2; extern unsigned IOCTL_SOUND_MIXER_READ_LINE3; extern unsigned IOCTL_SOUND_MIXER_READ_LINE; extern unsigned IOCTL_SOUND_MIXER_READ_LOUD; extern unsigned IOCTL_SOUND_MIXER_READ_MIC; extern unsigned IOCTL_SOUND_MIXER_READ_MUTE; extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN; extern unsigned IOCTL_SOUND_MIXER_READ_PCM; extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV; extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK; extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC; extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER; extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS; extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH; extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE; extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME; extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM; extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS; extern unsigned IOCTL_SOUND_MIXER_WRITE_CD; extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE; extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN; extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX; extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1; extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2; extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3; extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE; extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD; extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC; extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE; extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN; extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM; extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV; extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC; extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER; extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH; extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE; extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME; extern unsigned IOCTL_SOUND_PCM_READ_BITS; extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS; extern unsigned IOCTL_SOUND_PCM_READ_FILTER; extern unsigned IOCTL_SOUND_PCM_READ_RATE; extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS; extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER; extern unsigned IOCTL_VT_ACTIVATE; extern unsigned IOCTL_VT_GETMODE; extern unsigned IOCTL_VT_OPENQRY; extern unsigned IOCTL_VT_RELDISP; extern unsigned IOCTL_VT_SETMODE; extern unsigned IOCTL_VT_WAITACTIVE; #endif // SANITIZER_LINUX || SANITIZER_FREEBSD #if SANITIZER_LINUX && !SANITIZER_ANDROID extern unsigned IOCTL_CYGETDEFTHRESH; extern unsigned IOCTL_CYGETDEFTIMEOUT; extern unsigned IOCTL_CYGETMON; extern unsigned IOCTL_CYGETTHRESH; extern unsigned IOCTL_CYGETTIMEOUT; extern unsigned IOCTL_CYSETDEFTHRESH; extern unsigned IOCTL_CYSETDEFTIMEOUT; extern unsigned IOCTL_CYSETTHRESH; extern unsigned IOCTL_CYSETTIMEOUT; extern unsigned IOCTL_EQL_EMANCIPATE; extern unsigned IOCTL_EQL_ENSLAVE; extern unsigned IOCTL_EQL_GETMASTRCFG; extern unsigned IOCTL_EQL_GETSLAVECFG; extern unsigned IOCTL_EQL_SETMASTRCFG; extern unsigned IOCTL_EQL_SETSLAVECFG; extern unsigned IOCTL_EVIOCGKEYCODE_V2; extern unsigned IOCTL_EVIOCGPROP; extern unsigned IOCTL_EVIOCSKEYCODE_V2; extern unsigned IOCTL_FS_IOC_GETFLAGS; extern unsigned IOCTL_FS_IOC_GETVERSION; extern unsigned IOCTL_FS_IOC_SETFLAGS; extern unsigned IOCTL_FS_IOC_SETVERSION; extern unsigned IOCTL_GIO_CMAP; extern unsigned IOCTL_GIO_FONT; extern unsigned IOCTL_GIO_UNIMAP; extern unsigned IOCTL_GIO_UNISCRNMAP; extern unsigned IOCTL_KDADDIO; extern unsigned IOCTL_KDDELIO; extern unsigned IOCTL_KDGETKEYCODE; extern unsigned IOCTL_KDGKBDIACR; extern unsigned IOCTL_KDGKBENT; extern unsigned IOCTL_KDGKBLED; extern unsigned IOCTL_KDGKBMETA; extern unsigned IOCTL_KDGKBSENT; extern unsigned IOCTL_KDMAPDISP; extern unsigned IOCTL_KDSETKEYCODE; extern unsigned IOCTL_KDSIGACCEPT; extern unsigned IOCTL_KDSKBDIACR; extern unsigned IOCTL_KDSKBENT; extern unsigned IOCTL_KDSKBLED; extern unsigned IOCTL_KDSKBMETA; extern unsigned IOCTL_KDSKBSENT; extern unsigned IOCTL_KDUNMAPDISP; extern unsigned IOCTL_LPABORT; extern unsigned IOCTL_LPABORTOPEN; extern unsigned IOCTL_LPCAREFUL; extern unsigned IOCTL_LPCHAR; extern unsigned IOCTL_LPGETIRQ; extern unsigned IOCTL_LPGETSTATUS; extern unsigned IOCTL_LPRESET; extern unsigned IOCTL_LPSETIRQ; extern unsigned IOCTL_LPTIME; extern unsigned IOCTL_LPWAIT; extern unsigned IOCTL_MTIOCGETCONFIG; extern unsigned IOCTL_MTIOCSETCONFIG; extern unsigned IOCTL_PIO_CMAP; extern unsigned IOCTL_PIO_FONT; extern unsigned IOCTL_PIO_UNIMAP; extern unsigned IOCTL_PIO_UNIMAPCLR; extern unsigned IOCTL_PIO_UNISCRNMAP; extern unsigned IOCTL_SCSI_IOCTL_GET_IDLUN; extern unsigned IOCTL_SCSI_IOCTL_PROBE_HOST; extern unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE; extern unsigned IOCTL_SCSI_IOCTL_TAGGED_ENABLE; extern unsigned IOCTL_SIOCAIPXITFCRT; extern unsigned IOCTL_SIOCAIPXPRISLT; extern unsigned IOCTL_SIOCAX25ADDUID; extern unsigned IOCTL_SIOCAX25DELUID; extern unsigned IOCTL_SIOCAX25GETPARMS; extern unsigned IOCTL_SIOCAX25GETUID; extern unsigned IOCTL_SIOCAX25NOUID; extern unsigned IOCTL_SIOCAX25SETPARMS; extern unsigned IOCTL_SIOCDEVPLIP; extern unsigned IOCTL_SIOCIPXCFGDATA; extern unsigned IOCTL_SIOCNRDECOBS; extern unsigned IOCTL_SIOCNRGETPARMS; extern unsigned IOCTL_SIOCNRRTCTL; extern unsigned IOCTL_SIOCNRSETPARMS; extern unsigned IOCTL_SNDCTL_DSP_GETISPACE; extern unsigned IOCTL_SNDCTL_DSP_GETOSPACE; extern unsigned IOCTL_TIOCGSERIAL; extern unsigned IOCTL_TIOCSERGETMULTI; extern unsigned IOCTL_TIOCSERSETMULTI; extern unsigned IOCTL_TIOCSSERIAL; #endif // SANITIZER_LINUX && !SANITIZER_ANDROID #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID extern unsigned IOCTL_GIO_SCRNMAP; extern unsigned IOCTL_KDDISABIO; extern unsigned IOCTL_KDENABIO; extern unsigned IOCTL_KDGETLED; extern unsigned IOCTL_KDGETMODE; extern unsigned IOCTL_KDGKBMODE; extern unsigned IOCTL_KDGKBTYPE; extern unsigned IOCTL_KDMKTONE; extern unsigned IOCTL_KDSETLED; extern unsigned IOCTL_KDSETMODE; extern unsigned IOCTL_KDSKBMODE; extern unsigned IOCTL_KIOCSOUND; extern unsigned IOCTL_PIO_SCRNMAP; #endif extern const int errno_EINVAL; extern const int errno_EOWNERDEAD; extern const int si_SEGV_MAPERR; extern const int si_SEGV_ACCERR; } // namespace __sanitizer #define CHECK_TYPE_SIZE(TYPE) \ COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) #define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *) NULL)->MEMBER) == \ sizeof(((CLASS *) NULL)->MEMBER)); \ COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ offsetof(CLASS, MEMBER)) // For sigaction, which is a function and struct at the same time, // and thus requires explicit "struct" in sizeof() expression. #define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *) NULL)->MEMBER) == \ sizeof(((struct CLASS *) NULL)->MEMBER)); \ COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ offsetof(struct CLASS, MEMBER)) #endif Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc (revision 279194) @@ -1,462 +1,468 @@ //===-- sanitizer_stoptheworld_linux_libcdep.cc ---------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // See sanitizer_stoptheworld.h for details. // This implementation was inspired by Markus Gutschke's linuxthreads.cc. // //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" -#if SANITIZER_LINUX && defined(__x86_64__) +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)) #include "sanitizer_stoptheworld.h" #include "sanitizer_platform_limits_posix.h" #include #include // for CLONE_* definitions #include #include // for PR_* definitions #include // for PTRACE_* definitions #include // for pid_t #if SANITIZER_ANDROID && defined(__arm__) # include // for pt_regs #else # include // for user_regs_struct #endif #include // for signal-related stuff #ifdef sa_handler # undef sa_handler #endif #ifdef sa_sigaction # undef sa_sigaction #endif #include "sanitizer_common.h" #include "sanitizer_flags.h" #include "sanitizer_libc.h" #include "sanitizer_linux.h" #include "sanitizer_mutex.h" #include "sanitizer_placement_new.h" // This module works by spawning a Linux task which then attaches to every // thread in the caller process with ptrace. This suspends the threads, and // PTRACE_GETREGS can then be used to obtain their register state. The callback // supplied to StopTheWorld() is run in the tracer task while the threads are // suspended. // The tracer task must be placed in a different thread group for ptrace to // work, so it cannot be spawned as a pthread. Instead, we use the low-level // clone() interface (we want to share the address space with the caller // process, so we prefer clone() over fork()). // // We don't use any libc functions, relying instead on direct syscalls. There // are two reasons for this: // 1. calling a library function while threads are suspended could cause a // deadlock, if one of the treads happens to be holding a libc lock; // 2. it's generally not safe to call libc functions from the tracer task, // because clone() does not set up a thread-local storage for it. Any // thread-local variables used by libc will be shared between the tracer task // and the thread which spawned it. COMPILER_CHECK(sizeof(SuspendedThreadID) == sizeof(pid_t)); namespace __sanitizer { // This class handles thread suspending/unsuspending in the tracer thread. class ThreadSuspender { public: explicit ThreadSuspender(pid_t pid) : pid_(pid) { CHECK_GE(pid, 0); } bool SuspendAllThreads(); void ResumeAllThreads(); void KillAllThreads(); SuspendedThreadsList &suspended_threads_list() { return suspended_threads_list_; } private: SuspendedThreadsList suspended_threads_list_; pid_t pid_; bool SuspendThread(SuspendedThreadID thread_id); }; -bool ThreadSuspender::SuspendThread(SuspendedThreadID thread_id) { +bool ThreadSuspender::SuspendThread(SuspendedThreadID tid) { // Are we already attached to this thread? // Currently this check takes linear time, however the number of threads is // usually small. - if (suspended_threads_list_.Contains(thread_id)) + if (suspended_threads_list_.Contains(tid)) return false; int pterrno; - if (internal_iserror(internal_ptrace(PTRACE_ATTACH, thread_id, NULL, NULL), + if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, NULL, NULL), &pterrno)) { // Either the thread is dead, or something prevented us from attaching. // Log this event and move on. - VReport(1, "Could not attach to thread %d (errno %d).\n", thread_id, - pterrno); + VReport(1, "Could not attach to thread %d (errno %d).\n", tid, pterrno); return false; } else { - VReport(1, "Attached to thread %d.\n", thread_id); + VReport(1, "Attached to thread %d.\n", tid); // The thread is not guaranteed to stop before ptrace returns, so we must - // wait on it. - uptr waitpid_status; - HANDLE_EINTR(waitpid_status, internal_waitpid(thread_id, NULL, __WALL)); - int wperrno; - if (internal_iserror(waitpid_status, &wperrno)) { - // Got a ECHILD error. I don't think this situation is possible, but it - // doesn't hurt to report it. - VReport(1, "Waiting on thread %d failed, detaching (errno %d).\n", - thread_id, wperrno); - internal_ptrace(PTRACE_DETACH, thread_id, NULL, NULL); - return false; + // wait on it. Note: if the thread receives a signal concurrently, + // we can get notification about the signal before notification about stop. + // In such case we need to forward the signal to the thread, otherwise + // the signal will be missed (as we do PTRACE_DETACH with arg=0) and + // any logic relying on signals will break. After forwarding we need to + // continue to wait for stopping, because the thread is not stopped yet. + // We do ignore delivery of SIGSTOP, because we want to make stop-the-world + // as invisible as possible. + for (;;) { + int status; + uptr waitpid_status; + HANDLE_EINTR(waitpid_status, internal_waitpid(tid, &status, __WALL)); + int wperrno; + if (internal_iserror(waitpid_status, &wperrno)) { + // Got a ECHILD error. I don't think this situation is possible, but it + // doesn't hurt to report it. + VReport(1, "Waiting on thread %d failed, detaching (errno %d).\n", + tid, wperrno); + internal_ptrace(PTRACE_DETACH, tid, NULL, NULL); + return false; + } + if (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) { + internal_ptrace(PTRACE_CONT, tid, 0, (void*)(uptr)WSTOPSIG(status)); + continue; + } + break; } - suspended_threads_list_.Append(thread_id); + suspended_threads_list_.Append(tid); return true; } } void ThreadSuspender::ResumeAllThreads() { for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++) { pid_t tid = suspended_threads_list_.GetThreadID(i); int pterrno; if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, NULL, NULL), &pterrno)) { VReport(1, "Detached from thread %d.\n", tid); } else { // Either the thread is dead, or we are already detached. // The latter case is possible, for instance, if this function was called // from a signal handler. VReport(1, "Could not detach from thread %d (errno %d).\n", tid, pterrno); } } } void ThreadSuspender::KillAllThreads() { for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++) internal_ptrace(PTRACE_KILL, suspended_threads_list_.GetThreadID(i), NULL, NULL); } bool ThreadSuspender::SuspendAllThreads() { ThreadLister thread_lister(pid_); bool added_threads; do { // Run through the directory entries once. added_threads = false; pid_t tid = thread_lister.GetNextTID(); while (tid >= 0) { if (SuspendThread(tid)) added_threads = true; tid = thread_lister.GetNextTID(); } if (thread_lister.error()) { // Detach threads and fail. ResumeAllThreads(); return false; } thread_lister.Reset(); } while (added_threads); return true; } // Pointer to the ThreadSuspender instance for use in signal handler. static ThreadSuspender *thread_suspender_instance = NULL; -// Signals that should not be blocked (this is used in the parent thread as well -// as the tracer thread). -static const int kUnblockedSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV, - SIGBUS, SIGXCPU, SIGXFSZ }; +// Synchronous signals that should not be blocked. +static const int kSyncSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV, SIGBUS, + SIGXCPU, SIGXFSZ }; // Structure for passing arguments into the tracer thread. struct TracerThreadArgument { StopTheWorldCallback callback; void *callback_argument; // The tracer thread waits on this mutex while the parent finishes its // preparations. BlockingMutex mutex; uptr parent_pid; }; static DieCallbackType old_die_callback; // Signal handler to wake up suspended threads when the tracer thread dies. -void TracerThreadSignalHandler(int signum, void *siginfo, void *) { +static void TracerThreadSignalHandler(int signum, void *siginfo, void *) { if (thread_suspender_instance != NULL) { if (signum == SIGABRT) thread_suspender_instance->KillAllThreads(); else thread_suspender_instance->ResumeAllThreads(); } internal__exit((signum == SIGABRT) ? 1 : 2); } static void TracerThreadDieCallback() { // Generally a call to Die() in the tracer thread should be fatal to the // parent process as well, because they share the address space. // This really only works correctly if all the threads are suspended at this // point. So we correctly handle calls to Die() from within the callback, but // not those that happen before or after the callback. Hopefully there aren't // a lot of opportunities for that to happen... if (thread_suspender_instance) thread_suspender_instance->KillAllThreads(); if (old_die_callback) old_die_callback(); } // Size of alternative stack for signal handlers in the tracer thread. static const int kHandlerStackSize = 4096; // This function will be run as a cloned task. static int TracerThread(void* argument) { TracerThreadArgument *tracer_thread_argument = (TracerThreadArgument *)argument; internal_prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // Check if parent is already dead. if (internal_getppid() != tracer_thread_argument->parent_pid) internal__exit(4); // Wait for the parent thread to finish preparations. tracer_thread_argument->mutex.Lock(); tracer_thread_argument->mutex.Unlock(); + old_die_callback = GetDieCallback(); SetDieCallback(TracerThreadDieCallback); ThreadSuspender thread_suspender(internal_getppid()); // Global pointer for the signal handler. thread_suspender_instance = &thread_suspender; // Alternate stack for signal handling. InternalScopedBuffer handler_stack_memory(kHandlerStackSize); struct sigaltstack handler_stack; internal_memset(&handler_stack, 0, sizeof(handler_stack)); handler_stack.ss_sp = handler_stack_memory.data(); handler_stack.ss_size = kHandlerStackSize; internal_sigaltstack(&handler_stack, NULL); - // Install our handler for fatal signals. Other signals should be blocked by - // the mask we inherited from the caller thread. - for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals); - signal_index++) { - __sanitizer_sigaction new_sigaction; - internal_memset(&new_sigaction, 0, sizeof(new_sigaction)); - new_sigaction.sigaction = TracerThreadSignalHandler; - new_sigaction.sa_flags = SA_ONSTACK | SA_SIGINFO; - internal_sigfillset(&new_sigaction.sa_mask); - internal_sigaction_norestorer(kUnblockedSignals[signal_index], - &new_sigaction, NULL); + // Install our handler for synchronous signals. Other signals should be + // blocked by the mask we inherited from the parent thread. + for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) { + __sanitizer_sigaction act; + internal_memset(&act, 0, sizeof(act)); + act.sigaction = TracerThreadSignalHandler; + act.sa_flags = SA_ONSTACK | SA_SIGINFO; + internal_sigaction_norestorer(kSyncSignals[i], &act, 0); } int exit_code = 0; if (!thread_suspender.SuspendAllThreads()) { VReport(1, "Failed suspending threads.\n"); exit_code = 3; } else { tracer_thread_argument->callback(thread_suspender.suspended_threads_list(), tracer_thread_argument->callback_argument); thread_suspender.ResumeAllThreads(); exit_code = 0; } + // Note, this is a bad race. If TracerThreadDieCallback is already started + // in another thread and observed that thread_suspender_instance != 0, + // it can call KillAllThreads on the destroyed variable. + SetDieCallback(old_die_callback); thread_suspender_instance = NULL; - handler_stack.ss_flags = SS_DISABLE; - internal_sigaltstack(&handler_stack, NULL); return exit_code; } class ScopedStackSpaceWithGuard { public: explicit ScopedStackSpaceWithGuard(uptr stack_size) { stack_size_ = stack_size; guard_size_ = GetPageSizeCached(); // FIXME: Omitting MAP_STACK here works in current kernels but might break // in the future. guard_start_ = (uptr)MmapOrDie(stack_size_ + guard_size_, "ScopedStackWithGuard"); CHECK_EQ(guard_start_, (uptr)Mprotect((uptr)guard_start_, guard_size_)); } ~ScopedStackSpaceWithGuard() { UnmapOrDie((void *)guard_start_, stack_size_ + guard_size_); } void *Bottom() const { return (void *)(guard_start_ + stack_size_ + guard_size_); } private: uptr stack_size_; uptr guard_size_; uptr guard_start_; }; // We have a limitation on the stack frame size, so some stuff had to be moved // into globals. static __sanitizer_sigset_t blocked_sigset; static __sanitizer_sigset_t old_sigset; -static __sanitizer_sigaction old_sigactions - [ARRAY_SIZE(kUnblockedSignals)]; class StopTheWorldScope { public: StopTheWorldScope() { - // Block all signals that can be blocked safely, and install - // default handlers for the remaining signals. - // We cannot allow user-defined handlers to run while the ThreadSuspender - // thread is active, because they could conceivably call some libc functions - // which modify errno (which is shared between the two threads). - internal_sigfillset(&blocked_sigset); - for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals); - signal_index++) { - // Remove the signal from the set of blocked signals. - internal_sigdelset(&blocked_sigset, kUnblockedSignals[signal_index]); - // Install the default handler. - __sanitizer_sigaction new_sigaction; - internal_memset(&new_sigaction, 0, sizeof(new_sigaction)); - new_sigaction.handler = SIG_DFL; - internal_sigfillset(&new_sigaction.sa_mask); - internal_sigaction_norestorer(kUnblockedSignals[signal_index], - &new_sigaction, &old_sigactions[signal_index]); - } - int sigprocmask_status = - internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset); - CHECK_EQ(sigprocmask_status, 0); // sigprocmask should never fail // Make this process dumpable. Processes that are not dumpable cannot be // attached to. process_was_dumpable_ = internal_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0); if (!process_was_dumpable_) internal_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); - old_die_callback = GetDieCallback(); } ~StopTheWorldScope() { - SetDieCallback(old_die_callback); // Restore the dumpable flag. if (!process_was_dumpable_) internal_prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); - // Restore the signal handlers. - for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals); - signal_index++) { - internal_sigaction_norestorer(kUnblockedSignals[signal_index], - &old_sigactions[signal_index], NULL); - } - internal_sigprocmask(SIG_SETMASK, &old_sigset, &old_sigset); } private: int process_was_dumpable_; }; // When sanitizer output is being redirected to file (i.e. by using log_path), // the tracer should write to the parent's log instead of trying to open a new // file. Alert the logging code to the fact that we have a tracer. struct ScopedSetTracerPID { explicit ScopedSetTracerPID(uptr tracer_pid) { stoptheworld_tracer_pid = tracer_pid; stoptheworld_tracer_ppid = internal_getpid(); } ~ScopedSetTracerPID() { stoptheworld_tracer_pid = 0; stoptheworld_tracer_ppid = 0; } }; void StopTheWorld(StopTheWorldCallback callback, void *argument) { StopTheWorldScope in_stoptheworld; // Prepare the arguments for TracerThread. struct TracerThreadArgument tracer_thread_argument; tracer_thread_argument.callback = callback; tracer_thread_argument.callback_argument = argument; tracer_thread_argument.parent_pid = internal_getpid(); const uptr kTracerStackSize = 2 * 1024 * 1024; ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize); // Block the execution of TracerThread until after we have set ptrace // permissions. tracer_thread_argument.mutex.Lock(); + // Signal handling story. + // We don't want async signals to be delivered to the tracer thread, + // so we block all async signals before creating the thread. An async signal + // handler can temporary modify errno, which is shared with this thread. + // We ought to use pthread_sigmask here, because sigprocmask has undefined + // behavior in multithreaded programs. However, on linux sigprocmask is + // equivalent to pthread_sigmask with the exception that pthread_sigmask + // does not allow to block some signals used internally in pthread + // implementation. We are fine with blocking them here, we are really not + // going to pthread_cancel the thread. + // The tracer thread should not raise any synchronous signals. But in case it + // does, we setup a special handler for sync signals that properly kills the + // parent as well. Note: we don't pass CLONE_SIGHAND to clone, so handlers + // in the tracer thread won't interfere with user program. Double note: if a + // user does something along the lines of 'kill -11 pid', that can kill the + // process even if user setup own handler for SEGV. + // Thing to watch out for: this code should not change behavior of user code + // in any observable way. In particular it should not override user signal + // handlers. + internal_sigfillset(&blocked_sigset); + for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) + internal_sigdelset(&blocked_sigset, kSyncSignals[i]); + int rv = internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset); + CHECK_EQ(rv, 0); uptr tracer_pid = internal_clone( TracerThread, tracer_stack.Bottom(), CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED, &tracer_thread_argument, 0 /* parent_tidptr */, 0 /* newtls */, 0 /* child_tidptr */); + internal_sigprocmask(SIG_SETMASK, &old_sigset, 0); int local_errno = 0; if (internal_iserror(tracer_pid, &local_errno)) { VReport(1, "Failed spawning a tracer thread (errno %d).\n", local_errno); tracer_thread_argument.mutex.Unlock(); } else { ScopedSetTracerPID scoped_set_tracer_pid(tracer_pid); // On some systems we have to explicitly declare that we want to be traced // by the tracer thread. #ifdef PR_SET_PTRACER internal_prctl(PR_SET_PTRACER, tracer_pid, 0, 0, 0); #endif // Allow the tracer thread to start. tracer_thread_argument.mutex.Unlock(); // Since errno is shared between this thread and the tracer thread, we // must avoid using errno while the tracer thread is running. // At this point, any signal will either be blocked or kill us, so waitpid // should never return (and set errno) while the tracer thread is alive. uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL); if (internal_iserror(waitpid_status, &local_errno)) VReport(1, "Waiting on the tracer thread failed (errno %d).\n", local_errno); } } // Platform-specific methods from SuspendedThreadsList. #if SANITIZER_ANDROID && defined(__arm__) typedef pt_regs regs_struct; #define REG_SP ARM_sp #elif SANITIZER_LINUX && defined(__arm__) typedef user_regs regs_struct; #define REG_SP uregs[13] #elif defined(__i386__) || defined(__x86_64__) typedef user_regs_struct regs_struct; #if defined(__i386__) #define REG_SP esp #else #define REG_SP rsp #endif #elif defined(__powerpc__) || defined(__powerpc64__) typedef pt_regs regs_struct; #define REG_SP gpr[PT_R1] #elif defined(__mips__) typedef struct user regs_struct; #define REG_SP regs[EF_REG29] #else #error "Unsupported architecture" #endif // SANITIZER_ANDROID && defined(__arm__) int SuspendedThreadsList::GetRegistersAndSP(uptr index, uptr *buffer, uptr *sp) const { pid_t tid = GetThreadID(index); regs_struct regs; int pterrno; if (internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, ®s), &pterrno)) { VReport(1, "Could not get registers from thread %d (errno %d).\n", tid, pterrno); return -1; } *sp = regs.REG_SP; internal_memcpy(buffer, ®s, sizeof(regs)); return 0; } uptr SuspendedThreadsList::RegisterCount() { return sizeof(regs_struct) / sizeof(uptr); } } // namespace __sanitizer -#endif // SANITIZER_LINUX && defined(__x86_64__) +#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)) Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.cc (revision 279194) @@ -1,194 +1,139 @@ //===-- sanitizer_suppressions.cc -----------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // -// Suppression parsing/matching code shared between TSan and LSan. +// Suppression parsing/matching code. // //===----------------------------------------------------------------------===// #include "sanitizer_suppressions.h" #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" #include "sanitizer_flags.h" #include "sanitizer_libc.h" #include "sanitizer_placement_new.h" namespace __sanitizer { -static const char *const kTypeStrings[SuppressionTypeCount] = { - "none", "race", "mutex", "thread", "signal", "leak", "called_from_lib", - "deadlock", "vptr_check", "interceptor_name", "interceptor_via_fun", - "interceptor_via_lib"}; - -bool TemplateMatch(char *templ, const char *str) { - if (str == 0 || str[0] == 0) - return false; - bool start = false; - if (templ && templ[0] == '^') { - start = true; - templ++; - } - bool asterisk = false; - while (templ && templ[0]) { - if (templ[0] == '*') { - templ++; - start = false; - asterisk = true; - continue; - } - if (templ[0] == '$') - return str[0] == 0 || asterisk; - if (str[0] == 0) - return false; - char *tpos = (char*)internal_strchr(templ, '*'); - char *tpos1 = (char*)internal_strchr(templ, '$'); - if (tpos == 0 || (tpos1 && tpos1 < tpos)) - tpos = tpos1; - if (tpos != 0) - tpos[0] = 0; - const char *str0 = str; - const char *spos = internal_strstr(str, templ); - str = spos + internal_strlen(templ); - templ = tpos; - if (tpos) - tpos[0] = tpos == tpos1 ? '$' : '*'; - if (spos == 0) - return false; - if (start && spos != str0) - return false; - start = false; - asterisk = false; - } - return true; +SuppressionContext::SuppressionContext(const char *suppression_types[], + int suppression_types_num) + : suppression_types_(suppression_types), + suppression_types_num_(suppression_types_num), suppressions_(1), + can_parse_(true) { + CHECK_LE(suppression_types_num_, kMaxSuppressionTypes); + internal_memset(has_suppression_type_, 0, suppression_types_num_); } -ALIGNED(64) static char placeholder[sizeof(SuppressionContext)]; -static SuppressionContext *suppression_ctx = 0; - -SuppressionContext::SuppressionContext() : suppressions_(1), can_parse_(true) { - internal_memset(has_suppresson_type_, 0, sizeof(has_suppresson_type_)); -} - -SuppressionContext *SuppressionContext::Get() { - CHECK(suppression_ctx); - return suppression_ctx; -} - -void SuppressionContext::InitIfNecessary() { - if (suppression_ctx) +void SuppressionContext::ParseFromFile(const char *filename) { + if (filename[0] == '\0') return; - suppression_ctx = new(placeholder) SuppressionContext; - if (common_flags()->suppressions[0] == '\0') - return; - char *suppressions_from_file; + char *file_contents; uptr buffer_size; - uptr contents_size = - ReadFileToBuffer(common_flags()->suppressions, &suppressions_from_file, - &buffer_size, 1 << 26 /* max_len */); + uptr contents_size = ReadFileToBuffer(filename, &file_contents, &buffer_size, + 1 << 26 /* max_len */); if (contents_size == 0) { Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName, - common_flags()->suppressions); + filename); Die(); } - suppression_ctx->Parse(suppressions_from_file); + Parse(file_contents); } -bool SuppressionContext::Match(const char *str, SuppressionType type, +bool SuppressionContext::Match(const char *str, const char *type, Suppression **s) { - if (!has_suppresson_type_[type]) - return false; can_parse_ = false; - uptr i; - for (i = 0; i < suppressions_.size(); i++) - if (type == suppressions_[i].type && - TemplateMatch(suppressions_[i].templ, str)) - break; - if (i == suppressions_.size()) return false; - *s = &suppressions_[i]; - return true; + if (!HasSuppressionType(type)) + return false; + for (uptr i = 0; i < suppressions_.size(); i++) { + Suppression &cur = suppressions_[i]; + if (0 == internal_strcmp(cur.type, type) && TemplateMatch(cur.templ, str)) { + *s = &cur; + return true; + } + } + return false; } static const char *StripPrefix(const char *str, const char *prefix) { while (str && *str == *prefix) { str++; prefix++; } if (!*prefix) return str; return 0; } void SuppressionContext::Parse(const char *str) { // Context must not mutate once Match has been called. CHECK(can_parse_); const char *line = str; while (line) { while (line[0] == ' ' || line[0] == '\t') line++; const char *end = internal_strchr(line, '\n'); if (end == 0) end = line + internal_strlen(line); if (line != end && line[0] != '#') { const char *end2 = end; while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t')) end2--; int type; - for (type = 0; type < SuppressionTypeCount; type++) { - const char *next_char = StripPrefix(line, kTypeStrings[type]); + for (type = 0; type < suppression_types_num_; type++) { + const char *next_char = StripPrefix(line, suppression_types_[type]); if (next_char && *next_char == ':') { line = ++next_char; break; } } - if (type == SuppressionTypeCount) { + if (type == suppression_types_num_) { Printf("%s: failed to parse suppressions\n", SanitizerToolName); Die(); } Suppression s; - s.type = static_cast(type); + s.type = suppression_types_[type]; s.templ = (char*)InternalAlloc(end2 - line + 1); internal_memcpy(s.templ, line, end2 - line); s.templ[end2 - line] = 0; s.hit_count = 0; s.weight = 0; suppressions_.push_back(s); - has_suppresson_type_[s.type] = true; + has_suppression_type_[type] = true; } if (end[0] == 0) break; line = end + 1; } } uptr SuppressionContext::SuppressionCount() const { return suppressions_.size(); } -bool SuppressionContext::HasSuppressionType(SuppressionType type) const { - return has_suppresson_type_[type]; +bool SuppressionContext::HasSuppressionType(const char *type) const { + for (int i = 0; i < suppression_types_num_; i++) { + if (0 == internal_strcmp(type, suppression_types_[i])) + return has_suppression_type_[i]; + } + return false; } const Suppression *SuppressionContext::SuppressionAt(uptr i) const { CHECK_LT(i, suppressions_.size()); return &suppressions_[i]; } void SuppressionContext::GetMatched( InternalMmapVector *matched) { for (uptr i = 0; i < suppressions_.size(); i++) if (suppressions_[i].hit_count) matched->push_back(&suppressions_[i]); -} - -const char *SuppressionTypeString(SuppressionType t) { - CHECK(t < SuppressionTypeCount); - return kTypeStrings[t]; } } // namespace __sanitizer Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_suppressions.h (revision 279194) @@ -1,75 +1,55 @@ //===-- sanitizer_suppressions.h --------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // -// Suppression parsing/matching code shared between TSan and LSan. +// Suppression parsing/matching code. // //===----------------------------------------------------------------------===// #ifndef SANITIZER_SUPPRESSIONS_H #define SANITIZER_SUPPRESSIONS_H #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" namespace __sanitizer { -enum SuppressionType { - SuppressionNone, - SuppressionRace, - SuppressionMutex, - SuppressionThread, - SuppressionSignal, - SuppressionLeak, - SuppressionLib, - SuppressionDeadlock, - SuppressionVptrCheck, - SuppressionInterceptorName, - SuppressionInterceptorViaFunction, - SuppressionInterceptorViaLibrary, - SuppressionTypeCount -}; - struct Suppression { - SuppressionType type; + const char *type; char *templ; unsigned hit_count; uptr weight; }; class SuppressionContext { public: + // Create new SuppressionContext capable of parsing given suppression types. + SuppressionContext(const char *supprression_types[], + int suppression_types_num); + + void ParseFromFile(const char *filename); void Parse(const char *str); - bool Match(const char* str, SuppressionType type, Suppression **s); + + bool Match(const char *str, const char *type, Suppression **s); uptr SuppressionCount() const; - bool HasSuppressionType(SuppressionType type) const; + bool HasSuppressionType(const char *type) const; const Suppression *SuppressionAt(uptr i) const; void GetMatched(InternalMmapVector *matched); - // Create a SuppressionContext singleton if it hasn't been created earlier. - // Not thread safe. Must be called early during initialization (but after - // runtime flags are parsed). - static void InitIfNecessary(); - // Returns a SuppressionContext singleton. - static SuppressionContext *Get(); - private: - SuppressionContext(); + static const int kMaxSuppressionTypes = 16; + const char **const suppression_types_; + const int suppression_types_num_; + InternalMmapVector suppressions_; - bool has_suppresson_type_[SuppressionTypeCount]; + bool has_suppression_type_[kMaxSuppressionTypes]; bool can_parse_; - - friend class SuppressionContextTest; }; - -const char *SuppressionTypeString(SuppressionType t); - -bool TemplateMatch(char *templ, const char *str); } // namespace __sanitizer #endif // SANITIZER_SUPPRESSIONS_H Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cc (revision 279194) @@ -1,124 +1,158 @@ //===-- sanitizer_symbolizer_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 shared between AddressSanitizer and ThreadSanitizer // run-time libraries. // Windows-specific implementation of symbolizer parts. //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" #if SANITIZER_WINDOWS #include #include #pragma comment(lib, "dbghelp.lib") #include "sanitizer_symbolizer.h" namespace __sanitizer { class WinSymbolizer : public Symbolizer { public: WinSymbolizer() : initialized_(false) {} SymbolizedStack *SymbolizePC(uptr addr) override { SymbolizedStack *frame = SymbolizedStack::New(addr); BlockingMutexLock l(&dbghelp_mu_); - if (!initialized_) { - if (!TrySymInitialize()) { - // OK, maybe the client app has called SymInitialize already. - // That's a bit unfortunate for us as all the DbgHelp functions are - // single-threaded and we can't coordinate with the app. - // FIXME: Can we stop the other threads at this point? - // Anyways, we have to reconfigure stuff to make sure that SymInitialize - // has all the appropriate options set. - // Cross our fingers and reinitialize DbgHelp. - Report("*** WARNING: Failed to initialize DbgHelp! ***\n"); - Report("*** Most likely this means that the app is already ***\n"); - Report("*** using DbgHelp, possibly with incompatible flags. ***\n"); - Report("*** Due to technical reasons, symbolization might crash ***\n"); - Report("*** or produce wrong results. ***\n"); - SymCleanup(GetCurrentProcess()); - TrySymInitialize(); - } - initialized_ = true; - } + InitializeIfNeeded(); // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)]; PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; symbol->SizeOfStruct = sizeof(SYMBOL_INFO); symbol->MaxNameLen = MAX_SYM_NAME; DWORD64 offset = 0; BOOL got_objname = SymFromAddr(GetCurrentProcess(), (DWORD64)addr, &offset, symbol); if (!got_objname) return frame; DWORD unused; IMAGEHLP_LINE64 line_info; line_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64); BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), (DWORD64)addr, &unused, &line_info); frame->info.function = internal_strdup(symbol->Name); frame->info.function_offset = (uptr)offset; if (got_fileline) { frame->info.file = internal_strdup(line_info.FileName); frame->info.line = line_info.LineNumber; } IMAGEHLP_MODULE64 mod_info; internal_memset(&mod_info, 0, sizeof(mod_info)); mod_info.SizeOfStruct = sizeof(mod_info); if (SymGetModuleInfo64(GetCurrentProcess(), addr, &mod_info)) frame->info.FillAddressAndModuleInfo(addr, mod_info.ImageName, addr - (uptr)mod_info.BaseOfImage); return frame; } bool CanReturnFileLineInfo() override { return true; } const char *Demangle(const char *name) override { CHECK(initialized_); static char demangle_buffer[1000]; if (name[0] == '\01' && UnDecorateSymbolName(name + 1, demangle_buffer, sizeof(demangle_buffer), UNDNAME_NAME_ONLY)) return demangle_buffer; else return name; } // FIXME: Implement GetModuleNameAndOffsetForPC(). private: + void InitializeIfNeeded() { + if (initialized_) + return; + if (!TrySymInitialize()) { + // OK, maybe the client app has called SymInitialize already. + // That's a bit unfortunate for us as all the DbgHelp functions are + // single-threaded and we can't coordinate with the app. + // FIXME: Can we stop the other threads at this point? + // Anyways, we have to reconfigure stuff to make sure that SymInitialize + // has all the appropriate options set. + // Cross our fingers and reinitialize DbgHelp. + Report("*** WARNING: Failed to initialize DbgHelp! ***\n"); + Report("*** Most likely this means that the app is already ***\n"); + Report("*** using DbgHelp, possibly with incompatible flags. ***\n"); + Report("*** Due to technical reasons, symbolization might crash ***\n"); + Report("*** or produce wrong results. ***\n"); + SymCleanup(GetCurrentProcess()); + TrySymInitialize(); + } + initialized_ = true; + + // When an executable is run from a location different from the one where it + // was originally built, we may not see the nearby PDB files. + // To work around this, let's append the directory of the main module + // to the symbol search path. All the failures below are not fatal. + const size_t kSymPathSize = 2048; + static wchar_t path_buffer[kSymPathSize + 1 + MAX_PATH]; + if (!SymGetSearchPathW(GetCurrentProcess(), path_buffer, kSymPathSize)) { + Report("*** WARNING: Failed to SymGetSearchPathW ***\n"); + return; + } + size_t sz = wcslen(path_buffer); + if (sz) { + CHECK_EQ(0, wcscat_s(path_buffer, L";")); + sz++; + } + DWORD res = GetModuleFileNameW(NULL, path_buffer + sz, MAX_PATH); + if (res == 0 || res == MAX_PATH) { + Report("*** WARNING: Failed to getting the EXE directory ***\n"); + return; + } + // Write the zero character in place of the last backslash to get the + // directory of the main module at the end of path_buffer. + wchar_t *last_bslash = wcsrchr(path_buffer + sz, L'\\'); + CHECK_NE(last_bslash, 0); + *last_bslash = L'\0'; + if (!SymSetSearchPathW(GetCurrentProcess(), path_buffer)) { + Report("*** WARNING: Failed to SymSetSearchPathW\n"); + return; + } + } + bool TrySymInitialize() { SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES); return SymInitialize(GetCurrentProcess(), 0, TRUE); // FIXME: We don't call SymCleanup() on exit yet - should we? } // All DbgHelp functions are single threaded, so we should use a mutex to // serialize accesses. BlockingMutex dbghelp_mu_; bool initialized_; }; Symbolizer *Symbolizer::PlatformInit() { static bool called_once = false; CHECK(!called_once && "Shouldn't create more than one symbolizer"); called_once = true; return new(symbolizer_allocator_) WinSymbolizer(); } } // namespace __sanitizer #endif // _WIN32 Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc (revision 279194) @@ -1,34 +1,34 @@ //===-- sanitizer_syscall_generic.inc ---------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Generic implementations of internal_syscall and internal_iserror. // //===----------------------------------------------------------------------===// -#if SANITIZER_FREEBSD +#if SANITIZER_FREEBSD || SANITIZER_MAC # define SYSCALL(name) SYS_ ## name #else # define SYSCALL(name) __NR_ ## name #endif -#if SANITIZER_FREEBSD && defined(__x86_64__) +#if (SANITIZER_FREEBSD || SANITIZER_MAC) && defined(__x86_64__) # define internal_syscall __syscall # else # define internal_syscall syscall #endif bool internal_iserror(uptr retval, int *rverrno) { if (retval == (uptr)-1) { if (rverrno) *rverrno = errno; return true; } else { return false; } } Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc (revision 279194) @@ -1,621 +1,623 @@ //===-- sanitizer_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 shared between AddressSanitizer and ThreadSanitizer // run-time libraries and implements windows-specific functions from // sanitizer_libc.h. //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" #if SANITIZER_WINDOWS #define WIN32_LEAN_AND_MEAN #define NOGDI #include #include #include #include #include #include "sanitizer_common.h" #include "sanitizer_libc.h" #include "sanitizer_mutex.h" #include "sanitizer_placement_new.h" #include "sanitizer_stacktrace.h" namespace __sanitizer { #include "sanitizer_syscall_generic.inc" // --------------------- sanitizer_common.h uptr GetPageSize() { return 1U << 14; // FIXME: is this configurable? } uptr GetMmapGranularity() { return 1U << 16; // FIXME: is this configurable? } uptr GetMaxVirtualAddress() { SYSTEM_INFO si; GetSystemInfo(&si); return (uptr)si.lpMaximumApplicationAddress; } bool FileExists(const char *filename) { UNIMPLEMENTED(); } uptr internal_getpid() { return GetProcessId(GetCurrentProcess()); } // In contrast to POSIX, on Windows GetCurrentThreadId() // returns a system-unique identifier. uptr GetTid() { return GetCurrentThreadId(); } uptr GetThreadSelf() { return GetTid(); } #if !SANITIZER_GO void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, uptr *stack_bottom) { CHECK(stack_top); CHECK(stack_bottom); MEMORY_BASIC_INFORMATION mbi; CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0); // FIXME: is it possible for the stack to not be a single allocation? // Are these values what ASan expects to get (reserved, not committed; // including stack guard page) ? *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize; *stack_bottom = (uptr)mbi.AllocationBase; } #endif // #if !SANITIZER_GO void *MmapOrDie(uptr size, const char *mem_type) { void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (rv == 0) { Report("ERROR: %s failed to " "allocate 0x%zx (%zd) bytes of %s (error code: %d)\n", SanitizerToolName, size, size, mem_type, GetLastError()); CHECK("unable to mmap" && 0); } return rv; } void UnmapOrDie(void *addr, uptr size) { if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) { Report("ERROR: %s failed to " "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n", SanitizerToolName, size, size, addr, GetLastError()); CHECK("unable to unmap" && 0); } } void *MmapFixedNoReserve(uptr fixed_addr, uptr size) { // FIXME: is this really "NoReserve"? On Win32 this does not matter much, // but on Win64 it does. void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (p == 0) Report("ERROR: %s failed to " "allocate %p (%zd) bytes at %p (error code: %d)\n", SanitizerToolName, size, size, fixed_addr, GetLastError()); return p; } void *MmapFixedOrDie(uptr fixed_addr, uptr size) { return MmapFixedNoReserve(fixed_addr, size); } void *MmapNoReserveOrDie(uptr size, const char *mem_type) { // FIXME: make this really NoReserve? return MmapOrDie(size, mem_type); } void *Mprotect(uptr fixed_addr, uptr size) { void *res = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS); if (res == 0) Report("WARNING: %s failed to " "mprotect %p (%zd) bytes at %p (error code: %d)\n", SanitizerToolName, size, size, fixed_addr, GetLastError()); return res; } void FlushUnneededShadowMemory(uptr addr, uptr size) { // This is almost useless on 32-bits. // FIXME: add madvise-analog when we move to 64-bits. } void NoHugePagesInRegion(uptr addr, uptr size) { // FIXME: probably similar to FlushUnneededShadowMemory. } void DontDumpShadowMemory(uptr addr, uptr length) { // This is almost useless on 32-bits. // FIXME: add madvise-analog when we move to 64-bits. } bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { MEMORY_BASIC_INFORMATION mbi; CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi))); return mbi.Protect == PAGE_NOACCESS && (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end; } void *MapFileToMemory(const char *file_name, uptr *buff_size) { UNIMPLEMENTED(); } void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) { UNIMPLEMENTED(); } static const int kMaxEnvNameLength = 128; static const DWORD kMaxEnvValueLength = 32767; namespace { struct EnvVariable { char name[kMaxEnvNameLength]; char value[kMaxEnvValueLength]; }; } // namespace static const int kEnvVariables = 5; static EnvVariable env_vars[kEnvVariables]; static int num_env_vars; const char *GetEnv(const char *name) { // Note: this implementation caches the values of the environment variables // and limits their quantity. for (int i = 0; i < num_env_vars; i++) { if (0 == internal_strcmp(name, env_vars[i].name)) return env_vars[i].value; } CHECK_LT(num_env_vars, kEnvVariables); DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value, kMaxEnvValueLength); if (rv > 0 && rv < kMaxEnvValueLength) { CHECK_LT(internal_strlen(name), kMaxEnvNameLength); internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength); num_env_vars++; return env_vars[num_env_vars - 1].value; } return 0; } const char *GetPwd() { UNIMPLEMENTED(); } u32 GetUid() { UNIMPLEMENTED(); } namespace { struct ModuleInfo { HMODULE handle; uptr base_address; uptr end_address; }; int CompareModulesBase(const void *pl, const void *pr) { const ModuleInfo &l = *(ModuleInfo *)pl, &r = *(ModuleInfo *)pr; if (l.base_address < r.base_address) return -1; return l.base_address > r.base_address; } } // namespace +#ifndef SANITIZER_GO void DumpProcessMap() { Report("Dumping process modules:\n"); HANDLE cur_process = GetCurrentProcess(); // Query the list of modules. Start by assuming there are no more than 256 // modules and retry if that's not sufficient. ModuleInfo *modules; size_t num_modules; { HMODULE *hmodules = 0; uptr modules_buffer_size = sizeof(HMODULE) * 256; DWORD bytes_required; while (!hmodules) { hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__); CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size, &bytes_required)); if (bytes_required > modules_buffer_size) { // Either there turned out to be more than 256 hmodules, or new hmodules // could have loaded since the last try. Retry. UnmapOrDie(hmodules, modules_buffer_size); hmodules = 0; modules_buffer_size = bytes_required; } } num_modules = bytes_required / sizeof(HMODULE); modules = (ModuleInfo *)MmapOrDie(num_modules * sizeof(ModuleInfo), __FUNCTION__); for (size_t i = 0; i < num_modules; ++i) { modules[i].handle = hmodules[i]; MODULEINFO mi; if (!GetModuleInformation(cur_process, hmodules[i], &mi, sizeof(mi))) continue; modules[i].base_address = (uptr)mi.lpBaseOfDll; modules[i].end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; } UnmapOrDie(hmodules, modules_buffer_size); } qsort(modules, num_modules, sizeof(ModuleInfo), CompareModulesBase); for (size_t i = 0; i < num_modules; ++i) { const ModuleInfo &mi = modules[i]; char module_name[MAX_PATH]; - bool got_module_name = GetModuleFileNameEx( - cur_process, mi.handle, module_name, sizeof(module_name)); + bool got_module_name = GetModuleFileNameA( + mi.handle, module_name, sizeof(module_name)); if (mi.end_address != 0) { Printf("\t%p-%p %s\n", mi.base_address, mi.end_address, got_module_name ? module_name : "[no name]"); } else if (got_module_name) { Printf("\t??\?-??? %s\n", module_name); } else { Printf("\t???\n"); } } UnmapOrDie(modules, num_modules * sizeof(ModuleInfo)); } +#endif void DisableCoreDumperIfNecessary() { // Do nothing. } void ReExec() { UNIMPLEMENTED(); } void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { (void)args; // Nothing here for now. } bool StackSizeIsUnlimited() { UNIMPLEMENTED(); } void SetStackSizeLimitInBytes(uptr limit) { UNIMPLEMENTED(); } bool AddressSpaceIsUnlimited() { UNIMPLEMENTED(); } void SetAddressSpaceUnlimited() { UNIMPLEMENTED(); } char *FindPathToBinary(const char *name) { // Nothing here for now. return 0; } void SleepForSeconds(int seconds) { Sleep(seconds * 1000); } void SleepForMillis(int millis) { Sleep(millis); } u64 NanoTime() { return 0; } void Abort() { if (::IsDebuggerPresent()) __debugbreak(); internal__exit(3); } uptr GetListOfModules(LoadedModule *modules, uptr max_modules, string_predicate_t filter) { UNIMPLEMENTED(); }; #ifndef SANITIZER_GO int Atexit(void (*function)(void)) { return atexit(function); } #endif // ------------------ sanitizer_libc.h uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, u64 offset) { UNIMPLEMENTED(); } uptr internal_munmap(void *addr, uptr length) { UNIMPLEMENTED(); } uptr internal_close(fd_t fd) { UNIMPLEMENTED(); } int internal_isatty(fd_t fd) { return _isatty(fd); } uptr internal_open(const char *filename, int flags) { UNIMPLEMENTED(); } uptr internal_open(const char *filename, int flags, u32 mode) { UNIMPLEMENTED(); } uptr OpenFile(const char *filename, bool write) { UNIMPLEMENTED(); } uptr internal_read(fd_t fd, void *buf, uptr count) { UNIMPLEMENTED(); } uptr internal_write(fd_t fd, const void *buf, uptr count) { if (fd != kStderrFd) UNIMPLEMENTED(); static HANDLE output_stream = 0; // Abort immediately if we know printing is not possible. if (output_stream == INVALID_HANDLE_VALUE) return 0; // If called for the first time, try to use stderr to output stuff, // falling back to stdout if anything goes wrong. bool fallback_to_stdout = false; if (output_stream == 0) { output_stream = GetStdHandle(STD_ERROR_HANDLE); // We don't distinguish "no such handle" from error. if (output_stream == 0) output_stream = INVALID_HANDLE_VALUE; if (output_stream == INVALID_HANDLE_VALUE) { // Retry with stdout? output_stream = GetStdHandle(STD_OUTPUT_HANDLE); if (output_stream == 0) output_stream = INVALID_HANDLE_VALUE; if (output_stream == INVALID_HANDLE_VALUE) return 0; } else { // Successfully got an stderr handle. However, if WriteFile() fails, // we can still try to fallback to stdout. fallback_to_stdout = true; } } DWORD ret; if (WriteFile(output_stream, buf, count, &ret, 0)) return ret; // Re-try with stdout if using a valid stderr handle fails. if (fallback_to_stdout) { output_stream = GetStdHandle(STD_OUTPUT_HANDLE); if (output_stream == 0) output_stream = INVALID_HANDLE_VALUE; if (output_stream != INVALID_HANDLE_VALUE) return internal_write(fd, buf, count); } return 0; } uptr internal_stat(const char *path, void *buf) { UNIMPLEMENTED(); } uptr internal_lstat(const char *path, void *buf) { UNIMPLEMENTED(); } uptr internal_fstat(fd_t fd, void *buf) { UNIMPLEMENTED(); } uptr internal_filesize(fd_t fd) { UNIMPLEMENTED(); } uptr internal_dup2(int oldfd, int newfd) { UNIMPLEMENTED(); } uptr internal_readlink(const char *path, char *buf, uptr bufsize) { UNIMPLEMENTED(); } uptr internal_sched_yield() { Sleep(0); return 0; } void internal__exit(int exitcode) { ExitProcess(exitcode); } uptr internal_ftruncate(fd_t fd, uptr size) { UNIMPLEMENTED(); } uptr internal_rename(const char *oldpath, const char *newpath) { UNIMPLEMENTED(); } uptr GetRSS() { return 0; } void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; } void internal_join_thread(void *th) { } // ---------------------- BlockingMutex ---------------- {{{1 const uptr LOCK_UNINITIALIZED = 0; const uptr LOCK_READY = (uptr)-1; BlockingMutex::BlockingMutex(LinkerInitialized li) { // FIXME: see comments in BlockingMutex::Lock() for the details. CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED); CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); owner_ = LOCK_READY; } BlockingMutex::BlockingMutex() { CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); owner_ = LOCK_READY; } void BlockingMutex::Lock() { if (owner_ == LOCK_UNINITIALIZED) { // FIXME: hm, global BlockingMutex objects are not initialized?!? // This might be a side effect of the clang+cl+link Frankenbuild... new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1)); // FIXME: If it turns out the linker doesn't invoke our // constructors, we should probably manually Lock/Unlock all the global // locks while we're starting in one thread to avoid double-init races. } EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_); CHECK_EQ(owner_, LOCK_READY); owner_ = GetThreadSelf(); } void BlockingMutex::Unlock() { CHECK_EQ(owner_, GetThreadSelf()); owner_ = LOCK_READY; LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_); } void BlockingMutex::CheckLocked() { CHECK_EQ(owner_, GetThreadSelf()); } uptr GetTlsSize() { return 0; } void InitTlsSize() { } void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, uptr *tls_addr, uptr *tls_size) { #ifdef SANITIZER_GO *stk_addr = 0; *stk_size = 0; *tls_addr = 0; *tls_size = 0; #else uptr stack_top, stack_bottom; GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); *stk_addr = stack_bottom; *stk_size = stack_top - stack_bottom; *tls_addr = 0; *tls_size = 0; #endif } #if !SANITIZER_GO void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) { CHECK_GE(max_depth, 2); // FIXME: CaptureStackBackTrace might be too slow for us. // FIXME: Compare with StackWalk64. // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax), (void**)trace, 0); if (size == 0) return; // Skip the RTL frames by searching for the PC in the stacktrace. uptr pc_location = LocatePcInTrace(pc); PopStackFrames(pc_location); } void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, u32 max_depth) { CONTEXT ctx = *(CONTEXT *)context; STACKFRAME64 stack_frame; memset(&stack_frame, 0, sizeof(stack_frame)); size = 0; #if defined(_WIN64) int machine_type = IMAGE_FILE_MACHINE_AMD64; stack_frame.AddrPC.Offset = ctx.Rip; stack_frame.AddrFrame.Offset = ctx.Rbp; stack_frame.AddrStack.Offset = ctx.Rsp; #else int machine_type = IMAGE_FILE_MACHINE_I386; stack_frame.AddrPC.Offset = ctx.Eip; stack_frame.AddrFrame.Offset = ctx.Ebp; stack_frame.AddrStack.Offset = ctx.Esp; #endif stack_frame.AddrPC.Mode = AddrModeFlat; stack_frame.AddrFrame.Mode = AddrModeFlat; stack_frame.AddrStack.Mode = AddrModeFlat; while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(), &stack_frame, &ctx, NULL, &SymFunctionTableAccess64, &SymGetModuleBase64, NULL) && size < Min(max_depth, kStackTraceMax)) { trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset; } } #endif // #if !SANITIZER_GO void ReportFile::Write(const char *buffer, uptr length) { SpinMutexLock l(mu); ReopenIfNecessary(); if (length != internal_write(fd, buffer, length)) { // stderr may be closed, but we may be able to print to the debugger // instead. This is the case when launching a program from Visual Studio, // and the following routine should write to its console. OutputDebugStringA(buffer); } } void SetAlternateSignalStack() { // FIXME: Decide what to do on Windows. } void UnsetAlternateSignalStack() { // FIXME: Decide what to do on Windows. } void InstallDeadlySignalHandlers(SignalHandlerType handler) { (void)handler; // FIXME: Decide what to do on Windows. } bool IsDeadlySignal(int signum) { // FIXME: Decide what to do on Windows. return false; } bool IsAccessibleMemoryRange(uptr beg, uptr size) { // FIXME: Actually implement this function. return true; } } // namespace __sanitizer #endif // _WIN32 Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cc (revision 279194) @@ -1,260 +1,268 @@ //===-- sanitizer_linux_test.cc -------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Tests for sanitizer_linux.h // //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_LINUX #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_common.h" #include "gtest/gtest.h" #include #include #include #include #include namespace __sanitizer { struct TidReporterArgument { TidReporterArgument() { pthread_mutex_init(&terminate_thread_mutex, NULL); pthread_mutex_init(&tid_reported_mutex, NULL); pthread_cond_init(&terminate_thread_cond, NULL); pthread_cond_init(&tid_reported_cond, NULL); terminate_thread = false; } ~TidReporterArgument() { pthread_mutex_destroy(&terminate_thread_mutex); pthread_mutex_destroy(&tid_reported_mutex); pthread_cond_destroy(&terminate_thread_cond); pthread_cond_destroy(&tid_reported_cond); } pid_t reported_tid; // For signaling to spawned threads that they should terminate. pthread_cond_t terminate_thread_cond; pthread_mutex_t terminate_thread_mutex; bool terminate_thread; // For signaling to main thread that a child thread has reported its tid. pthread_cond_t tid_reported_cond; pthread_mutex_t tid_reported_mutex; private: // Disallow evil constructors TidReporterArgument(const TidReporterArgument &); void operator=(const TidReporterArgument &); }; class ThreadListerTest : public ::testing::Test { protected: virtual void SetUp() { pthread_t pthread_id; pid_t tid; for (uptr i = 0; i < kThreadCount; i++) { SpawnTidReporter(&pthread_id, &tid); pthread_ids_.push_back(pthread_id); tids_.push_back(tid); } } virtual void TearDown() { pthread_mutex_lock(&thread_arg.terminate_thread_mutex); thread_arg.terminate_thread = true; pthread_cond_broadcast(&thread_arg.terminate_thread_cond); pthread_mutex_unlock(&thread_arg.terminate_thread_mutex); for (uptr i = 0; i < pthread_ids_.size(); i++) pthread_join(pthread_ids_[i], NULL); } void SpawnTidReporter(pthread_t *pthread_id, pid_t *tid); static const uptr kThreadCount = 20; std::vector pthread_ids_; std::vector tids_; TidReporterArgument thread_arg; }; // Writes its TID once to reported_tid and waits until signaled to terminate. void *TidReporterThread(void *argument) { TidReporterArgument *arg = reinterpret_cast(argument); pthread_mutex_lock(&arg->tid_reported_mutex); arg->reported_tid = GetTid(); pthread_cond_broadcast(&arg->tid_reported_cond); pthread_mutex_unlock(&arg->tid_reported_mutex); pthread_mutex_lock(&arg->terminate_thread_mutex); while (!arg->terminate_thread) pthread_cond_wait(&arg->terminate_thread_cond, &arg->terminate_thread_mutex); pthread_mutex_unlock(&arg->terminate_thread_mutex); return NULL; } void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id, pid_t *tid) { pthread_mutex_lock(&thread_arg.tid_reported_mutex); thread_arg.reported_tid = -1; ASSERT_EQ(0, pthread_create(pthread_id, NULL, TidReporterThread, &thread_arg)); while (thread_arg.reported_tid == -1) pthread_cond_wait(&thread_arg.tid_reported_cond, &thread_arg.tid_reported_mutex); pthread_mutex_unlock(&thread_arg.tid_reported_mutex); *tid = thread_arg.reported_tid; } static std::vector ReadTidsToVector(ThreadLister *thread_lister) { std::vector listed_tids; pid_t tid; while ((tid = thread_lister->GetNextTID()) >= 0) listed_tids.push_back(tid); EXPECT_FALSE(thread_lister->error()); return listed_tids; } static bool Includes(std::vector first, std::vector second) { std::sort(first.begin(), first.end()); std::sort(second.begin(), second.end()); return std::includes(first.begin(), first.end(), second.begin(), second.end()); } static bool HasElement(std::vector vector, pid_t element) { return std::find(vector.begin(), vector.end(), element) != vector.end(); } // ThreadLister's output should include the current thread's TID and the TID of // every thread we spawned. TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) { pid_t self_tid = GetTid(); ThreadLister thread_lister(getpid()); std::vector listed_tids = ReadTidsToVector(&thread_lister); ASSERT_TRUE(HasElement(listed_tids, self_tid)); ASSERT_TRUE(Includes(listed_tids, tids_)); } // Calling Reset() should not cause ThreadLister to forget any threads it's // supposed to know about. TEST_F(ThreadListerTest, ResetDoesNotForgetThreads) { ThreadLister thread_lister(getpid()); // Run the loop body twice, because Reset() might behave differently if called // on a freshly created object. for (uptr i = 0; i < 2; i++) { thread_lister.Reset(); std::vector listed_tids = ReadTidsToVector(&thread_lister); ASSERT_TRUE(Includes(listed_tids, tids_)); } } // If new threads have spawned during ThreadLister object's lifetime, calling // Reset() should cause ThreadLister to recognize their existence. TEST_F(ThreadListerTest, ResetMakesNewThreadsKnown) { ThreadLister thread_lister(getpid()); std::vector threads_before_extra = ReadTidsToVector(&thread_lister); pthread_t extra_pthread_id; pid_t extra_tid; SpawnTidReporter(&extra_pthread_id, &extra_tid); // Register the new thread so it gets terminated in TearDown(). pthread_ids_.push_back(extra_pthread_id); // It would be very bizarre if the new TID had been listed before we even // spawned that thread, but it would also cause a false success in this test, // so better check for that. ASSERT_FALSE(HasElement(threads_before_extra, extra_tid)); thread_lister.Reset(); std::vector threads_after_extra = ReadTidsToVector(&thread_lister); ASSERT_TRUE(HasElement(threads_after_extra, extra_tid)); } TEST(SanitizerCommon, SetEnvTest) { const char kEnvName[] = "ENV_FOO"; SetEnv(kEnvName, "value"); EXPECT_STREQ("value", getenv(kEnvName)); unsetenv(kEnvName); EXPECT_EQ(0, getenv(kEnvName)); } #if defined(__x86_64__) || defined(__i386__) void *thread_self_offset_test_func(void *arg) { bool result = *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf(); return (void *)result; } TEST(SanitizerLinux, ThreadSelfOffset) { EXPECT_TRUE((bool)thread_self_offset_test_func(0)); pthread_t tid; void *result; ASSERT_EQ(0, pthread_create(&tid, 0, thread_self_offset_test_func, 0)); ASSERT_EQ(0, pthread_join(tid, &result)); EXPECT_TRUE((bool)result); } // libpthread puts the thread descriptor at the end of stack space. void *thread_descriptor_size_test_func(void *arg) { uptr descr_addr = ThreadSelf(); pthread_attr_t attr; pthread_getattr_np(pthread_self(), &attr); void *stackaddr; size_t stacksize; pthread_attr_getstack(&attr, &stackaddr, &stacksize); return (void *)((uptr)stackaddr + stacksize - descr_addr); } TEST(SanitizerLinux, ThreadDescriptorSize) { pthread_t tid; void *result; ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0)); ASSERT_EQ(0, pthread_join(tid, &result)); EXPECT_EQ((uptr)result, ThreadDescriptorSize()); } #endif TEST(SanitizerCommon, LibraryNameIs) { EXPECT_FALSE(LibraryNameIs("", "")); char full_name[256]; const char *paths[] = { "", "/", "/path/to/" }; const char *suffixes[] = { "", "-linux", ".1.2", "-linux.1.2" }; const char *base_names[] = { "lib", "lib.0", "lib-i386" }; const char *wrong_names[] = { "", "lib.9", "lib-x86_64" }; for (uptr i = 0; i < ARRAY_SIZE(paths); i++) for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) { for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) { internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so", paths[i], base_names[k], suffixes[j]); EXPECT_TRUE(LibraryNameIs(full_name, base_names[k])) << "Full name " << full_name << " doesn't match base name " << base_names[k]; for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++) EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m])) << "Full name " << full_name << " matches base name " << wrong_names[m]; } } } +#if defined(__mips64) +// Effectively, this is a test for ThreadDescriptorSize() which is used to +// compute ThreadSelf(). +TEST(SanitizerLinux, ThreadSelfTest) { + ASSERT_EQ(pthread_self(), ThreadSelf()); +} +#endif + } // namespace __sanitizer #endif // SANITIZER_LINUX Index: projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc (revision 279194) @@ -1,174 +1,134 @@ //===-- sanitizer_suppressions_test.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 ThreadSanitizer/AddressSanitizer runtime. // //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_suppressions.h" #include "gtest/gtest.h" #include namespace __sanitizer { static bool MyMatch(const char *templ, const char *func) { char tmp[1024]; strcpy(tmp, templ); // NOLINT return TemplateMatch(tmp, func); } TEST(Suppressions, Match) { EXPECT_TRUE(MyMatch("foobar$", "foobar")); EXPECT_TRUE(MyMatch("foobar", "foobar")); EXPECT_TRUE(MyMatch("*foobar*", "foobar")); EXPECT_TRUE(MyMatch("foobar", "prefix_foobar_postfix")); EXPECT_TRUE(MyMatch("*foobar*", "prefix_foobar_postfix")); EXPECT_TRUE(MyMatch("foo*bar", "foo_middle_bar")); EXPECT_TRUE(MyMatch("foo*bar", "foobar")); EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_bar_another_baz")); EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_barbaz")); EXPECT_TRUE(MyMatch("^foobar", "foobar")); EXPECT_TRUE(MyMatch("^foobar", "foobar_postfix")); EXPECT_TRUE(MyMatch("^*foobar", "foobar")); EXPECT_TRUE(MyMatch("^*foobar", "prefix_foobar")); EXPECT_TRUE(MyMatch("foobar$", "foobar")); EXPECT_TRUE(MyMatch("foobar$", "prefix_foobar")); EXPECT_TRUE(MyMatch("*foobar*$", "foobar")); EXPECT_TRUE(MyMatch("*foobar*$", "foobar_postfix")); EXPECT_TRUE(MyMatch("^foobar$", "foobar")); EXPECT_FALSE(MyMatch("foo", "baz")); EXPECT_FALSE(MyMatch("foobarbaz", "foobar")); EXPECT_FALSE(MyMatch("foobarbaz", "barbaz")); EXPECT_FALSE(MyMatch("foo*bar", "foobaz")); EXPECT_FALSE(MyMatch("foo*bar", "foo_baz")); EXPECT_FALSE(MyMatch("^foobar", "prefix_foobar")); EXPECT_FALSE(MyMatch("foobar$", "foobar_postfix")); EXPECT_FALSE(MyMatch("^foobar$", "prefix_foobar")); EXPECT_FALSE(MyMatch("^foobar$", "foobar_postfix")); EXPECT_FALSE(MyMatch("foo^bar", "foobar")); EXPECT_FALSE(MyMatch("foo$bar", "foobar")); EXPECT_FALSE(MyMatch("foo$^bar", "foobar")); } -TEST(Suppressions, TypeStrings) { - CHECK(!internal_strcmp(SuppressionTypeString(SuppressionNone), "none")); - CHECK(!internal_strcmp(SuppressionTypeString(SuppressionRace), "race")); - CHECK(!internal_strcmp(SuppressionTypeString(SuppressionMutex), "mutex")); - CHECK(!internal_strcmp(SuppressionTypeString(SuppressionThread), "thread")); - CHECK(!internal_strcmp(SuppressionTypeString(SuppressionSignal), "signal")); - CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLeak), "leak")); - CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLib), - "called_from_lib")); - CHECK( - !internal_strcmp(SuppressionTypeString(SuppressionDeadlock), "deadlock")); - CHECK(!internal_strcmp(SuppressionTypeString(SuppressionVptrCheck), - "vptr_check")); - CHECK(!internal_strcmp(SuppressionTypeString(SuppressionInterceptorName), - "interceptor_name")); - CHECK( - !internal_strcmp(SuppressionTypeString(SuppressionInterceptorViaFunction), - "interceptor_via_fun")); - CHECK( - !internal_strcmp(SuppressionTypeString(SuppressionInterceptorViaLibrary), - "interceptor_via_lib")); - // Ensure this test is up-to-date when suppression types are added. - CHECK_EQ(12, SuppressionTypeCount); -} +static const char *kTestSuppressionTypes[] = {"race", "thread", "mutex", + "signal"}; class SuppressionContextTest : public ::testing::Test { public: - virtual void SetUp() { ctx_ = new(placeholder_) SuppressionContext; } - virtual void TearDown() { ctx_->~SuppressionContext(); } + SuppressionContextTest() + : ctx_(kTestSuppressionTypes, ARRAY_SIZE(kTestSuppressionTypes)) {} protected: - InternalMmapVector *Suppressions() { - return &ctx_->suppressions_; + SuppressionContext ctx_; + + void CheckSuppressions(unsigned count, std::vector types, + std::vector templs) const { + EXPECT_EQ(count, ctx_.SuppressionCount()); + for (unsigned i = 0; i < count; i++) { + const Suppression *s = ctx_.SuppressionAt(i); + EXPECT_STREQ(types[i], s->type); + EXPECT_STREQ(templs[i], s->templ); + } } - SuppressionContext *ctx_; - ALIGNED(64) char placeholder_[sizeof(SuppressionContext)]; }; TEST_F(SuppressionContextTest, Parse) { - ctx_->Parse( - "race:foo\n" - " race:bar\n" // NOLINT - "race:baz \n" // NOLINT - "# a comment\n" - "race:quz\n" - ); // NOLINT - EXPECT_EQ((unsigned)4, ctx_->SuppressionCount()); - EXPECT_EQ((*Suppressions())[3].type, SuppressionRace); - EXPECT_EQ(0, strcmp((*Suppressions())[3].templ, "quz")); - EXPECT_EQ((*Suppressions())[2].type, SuppressionRace); - EXPECT_EQ(0, strcmp((*Suppressions())[2].templ, "baz")); - EXPECT_EQ((*Suppressions())[1].type, SuppressionRace); - EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar")); - EXPECT_EQ((*Suppressions())[0].type, SuppressionRace); - EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo")); + ctx_.Parse("race:foo\n" + " race:bar\n" // NOLINT + "race:baz \n" // NOLINT + "# a comment\n" + "race:quz\n"); // NOLINT + CheckSuppressions(4, {"race", "race", "race", "race"}, + {"foo", "bar", "baz", "quz"}); } TEST_F(SuppressionContextTest, Parse2) { - ctx_->Parse( + ctx_.Parse( " # first line comment\n" // NOLINT " race:bar \n" // NOLINT "race:baz* *baz\n" "# a comment\n" "# last line comment\n" ); // NOLINT - EXPECT_EQ((unsigned)2, ctx_->SuppressionCount()); - EXPECT_EQ((*Suppressions())[1].type, SuppressionRace); - EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "baz* *baz")); - EXPECT_EQ((*Suppressions())[0].type, SuppressionRace); - EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "bar")); + CheckSuppressions(2, {"race", "race"}, {"bar", "baz* *baz"}); } TEST_F(SuppressionContextTest, Parse3) { - ctx_->Parse( + ctx_.Parse( "# last suppression w/o line-feed\n" "race:foo\n" "race:bar" ); // NOLINT - EXPECT_EQ((unsigned)2, ctx_->SuppressionCount()); - EXPECT_EQ((*Suppressions())[1].type, SuppressionRace); - EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar")); - EXPECT_EQ((*Suppressions())[0].type, SuppressionRace); - EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo")); + CheckSuppressions(2, {"race", "race"}, {"foo", "bar"}); } TEST_F(SuppressionContextTest, ParseType) { - ctx_->Parse( + ctx_.Parse( "race:foo\n" "thread:bar\n" "mutex:baz\n" "signal:quz\n" ); // NOLINT - EXPECT_EQ((unsigned)4, ctx_->SuppressionCount()); - EXPECT_EQ((*Suppressions())[3].type, SuppressionSignal); - EXPECT_EQ(0, strcmp((*Suppressions())[3].templ, "quz")); - EXPECT_EQ((*Suppressions())[2].type, SuppressionMutex); - EXPECT_EQ(0, strcmp((*Suppressions())[2].templ, "baz")); - EXPECT_EQ((*Suppressions())[1].type, SuppressionThread); - EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar")); - EXPECT_EQ((*Suppressions())[0].type, SuppressionRace); - EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo")); + CheckSuppressions(4, {"race", "thread", "mutex", "signal"}, + {"foo", "bar", "baz", "quz"}); } TEST_F(SuppressionContextTest, HasSuppressionType) { - ctx_->Parse( + ctx_.Parse( "race:foo\n" "thread:bar\n"); - EXPECT_TRUE(ctx_->HasSuppressionType(SuppressionRace)); - EXPECT_TRUE(ctx_->HasSuppressionType(SuppressionThread)); - EXPECT_FALSE(ctx_->HasSuppressionType(SuppressionMutex)); - EXPECT_FALSE(ctx_->HasSuppressionType(SuppressionSignal)); + EXPECT_TRUE(ctx_.HasSuppressionType("race")); + EXPECT_TRUE(ctx_.HasSuppressionType("thread")); + EXPECT_FALSE(ctx_.HasSuppressionType("mutex")); + EXPECT_FALSE(ctx_.HasSuppressionType("signal")); } } // namespace __sanitizer Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/dd/dd_rtl.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/dd/dd_rtl.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/dd/dd_rtl.cc (revision 279194) @@ -1,159 +1,159 @@ //===-- dd_rtl.cc ---------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "dd_rtl.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_stackdepot.h" namespace __dsan { static Context *ctx; static u32 CurrentStackTrace(Thread *thr, uptr skip) { BufferedStackTrace stack; thr->ignore_interceptors = true; stack.Unwind(1000, 0, 0, 0, 0, 0, false); thr->ignore_interceptors = false; if (stack.size <= skip) return 0; return StackDepotPut(StackTrace(stack.trace + skip, stack.size - skip)); } static void PrintStackTrace(Thread *thr, u32 stk) { StackTrace stack = StackDepotGet(stk); thr->ignore_interceptors = true; stack.Print(); thr->ignore_interceptors = false; } static void ReportDeadlock(Thread *thr, DDReport *rep) { if (rep == 0) return; BlockingMutexLock lock(&ctx->report_mutex); Printf("==============================\n"); Printf("WARNING: lock-order-inversion (potential deadlock)\n"); for (int i = 0; i < rep->n; i++) { Printf("Thread %d locks mutex %llu while holding mutex %llu:\n", rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0); PrintStackTrace(thr, rep->loop[i].stk[1]); if (rep->loop[i].stk[0]) { Printf("Mutex %llu was acquired here:\n", rep->loop[i].mtx_ctx0); PrintStackTrace(thr, rep->loop[i].stk[0]); } } Printf("==============================\n"); } Callback::Callback(Thread *thr) : thr(thr) { lt = thr->dd_lt; pt = thr->dd_pt; } u32 Callback::Unwind() { return CurrentStackTrace(thr, 3); } -void InitializeFlags(Flags *f, const char *env) { - internal_memset(f, 0, sizeof(*f)); +static void InitializeFlags() { + Flags *f = flags(); // Default values. f->second_deadlock_stack = false; SetCommonFlagsDefaults(); { // Override some common flags defaults. CommonFlags cf; cf.CopyFrom(*common_flags()); cf.allow_addr2line = true; OverrideCommonFlags(cf); } // Override from command line. FlagParser parser; RegisterFlag(&parser, "second_deadlock_stack", "", &f->second_deadlock_stack); RegisterCommonFlags(&parser); - parser.ParseString(env); + parser.ParseString(GetEnv("DSAN_OPTIONS")); SetVerbosity(common_flags()->verbosity); } void Initialize() { static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1]; ctx = new(ctx_mem) Context(); InitializeInterceptors(); - InitializeFlags(flags(), GetEnv("DSAN_OPTIONS")); + InitializeFlags(); ctx->dd = DDetector::Create(flags()); } void ThreadInit(Thread *thr) { static atomic_uintptr_t id_gen; uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed); thr->dd_pt = ctx->dd->CreatePhysicalThread(); thr->dd_lt = ctx->dd->CreateLogicalThread(id); } void ThreadDestroy(Thread *thr) { ctx->dd->DestroyPhysicalThread(thr->dd_pt); ctx->dd->DestroyLogicalThread(thr->dd_lt); } void MutexBeforeLock(Thread *thr, uptr m, bool writelock) { if (thr->ignore_interceptors) return; Callback cb(thr); { MutexHashMap::Handle h(&ctx->mutex_map, m); if (h.created()) ctx->dd->MutexInit(&cb, &h->dd); ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock); } ReportDeadlock(thr, ctx->dd->GetReport(&cb)); } void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) { if (thr->ignore_interceptors) return; Callback cb(thr); { MutexHashMap::Handle h(&ctx->mutex_map, m); if (h.created()) ctx->dd->MutexInit(&cb, &h->dd); ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock); } ReportDeadlock(thr, ctx->dd->GetReport(&cb)); } void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) { if (thr->ignore_interceptors) return; Callback cb(thr); { MutexHashMap::Handle h(&ctx->mutex_map, m); ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock); } ReportDeadlock(thr, ctx->dd->GetReport(&cb)); } void MutexDestroy(Thread *thr, uptr m) { if (thr->ignore_interceptors) return; Callback cb(thr); MutexHashMap::Handle h(&ctx->mutex_map, m, true); if (!h.exists()) return; ctx->dd->MutexDestroy(&cb, &h->dd); } } // namespace __dsan Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/go/build.bat =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/go/build.bat (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/go/build.bat (revision 279194) @@ -1,4 +1,4 @@ -type tsan_go.cc ..\rtl\tsan_interface_atomic.cc ..\rtl\tsan_clock.cc ..\rtl\tsan_flags.cc ..\rtl\tsan_md5.cc ..\rtl\tsan_mutex.cc ..\rtl\tsan_report.cc ..\rtl\tsan_rtl.cc ..\rtl\tsan_rtl_mutex.cc ..\rtl\tsan_rtl_report.cc ..\rtl\tsan_rtl_thread.cc ..\rtl\tsan_stat.cc ..\rtl\tsan_suppressions.cc ..\rtl\tsan_sync.cc ..\rtl\tsan_stack_trace.cc ..\..\sanitizer_common\sanitizer_allocator.cc ..\..\sanitizer_common\sanitizer_common.cc ..\..\sanitizer_common\sanitizer_flags.cc ..\..\sanitizer_common\sanitizer_stacktrace.cc ..\..\sanitizer_common\sanitizer_libc.cc ..\..\sanitizer_common\sanitizer_printf.cc ..\..\sanitizer_common\sanitizer_suppressions.cc ..\..\sanitizer_common\sanitizer_thread_registry.cc ..\rtl\tsan_platform_windows.cc ..\..\sanitizer_common\sanitizer_win.cc ..\..\sanitizer_common\sanitizer_deadlock_detector1.cc ..\..\sanitizer_common\sanitizer_stackdepot.cc ..\..\sanitizer_common\sanitizer_persistent_allocator.cc > gotsan.cc +type tsan_go.cc ..\rtl\tsan_interface_atomic.cc ..\rtl\tsan_clock.cc ..\rtl\tsan_flags.cc ..\rtl\tsan_md5.cc ..\rtl\tsan_mutex.cc ..\rtl\tsan_report.cc ..\rtl\tsan_rtl.cc ..\rtl\tsan_rtl_mutex.cc ..\rtl\tsan_rtl_report.cc ..\rtl\tsan_rtl_thread.cc ..\rtl\tsan_stat.cc ..\rtl\tsan_suppressions.cc ..\rtl\tsan_sync.cc ..\rtl\tsan_stack_trace.cc ..\..\sanitizer_common\sanitizer_allocator.cc ..\..\sanitizer_common\sanitizer_common.cc ..\..\sanitizer_common\sanitizer_flags.cc ..\..\sanitizer_common\sanitizer_stacktrace.cc ..\..\sanitizer_common\sanitizer_libc.cc ..\..\sanitizer_common\sanitizer_printf.cc ..\..\sanitizer_common\sanitizer_suppressions.cc ..\..\sanitizer_common\sanitizer_thread_registry.cc ..\rtl\tsan_platform_windows.cc ..\..\sanitizer_common\sanitizer_win.cc ..\..\sanitizer_common\sanitizer_deadlock_detector1.cc ..\..\sanitizer_common\sanitizer_stackdepot.cc ..\..\sanitizer_common\sanitizer_persistent_allocator.cc ..\..\sanitizer_common\sanitizer_flag_parser.cc ..\..\sanitizer_common\sanitizer_symbolizer.cc > gotsan.cc -gcc -c -o race_windows_amd64.syso gotsan.cc -I..\rtl -I..\.. -I..\..\sanitizer_common -I..\..\..\include -m64 -Wall -fno-exceptions -fno-rtti -DSANITIZER_GO -Wno-error=attributes -Wno-attributes -Wno-format -DSANITIZER_DEBUG=0 -O3 -fomit-frame-pointer +gcc -c -o race_windows_amd64.syso gotsan.cc -I..\rtl -I..\.. -I..\..\sanitizer_common -I..\..\..\include -m64 -Wall -fno-exceptions -fno-rtti -DSANITIZER_GO -Wno-error=attributes -Wno-attributes -Wno-format -Wno-maybe-uninitialized -DSANITIZER_DEBUG=0 -O3 -fomit-frame-pointer -std=c++11 Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/go/buildgo.sh =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/go/buildgo.sh (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/go/buildgo.sh (revision 279194) @@ -1,132 +1,130 @@ #!/bin/sh set -e SRCS=" tsan_go.cc ../rtl/tsan_clock.cc ../rtl/tsan_flags.cc ../rtl/tsan_interface_atomic.cc ../rtl/tsan_md5.cc ../rtl/tsan_mutex.cc ../rtl/tsan_report.cc ../rtl/tsan_rtl.cc ../rtl/tsan_rtl_mutex.cc ../rtl/tsan_rtl_report.cc ../rtl/tsan_rtl_thread.cc ../rtl/tsan_stack_trace.cc ../rtl/tsan_stat.cc ../rtl/tsan_suppressions.cc ../rtl/tsan_sync.cc ../../sanitizer_common/sanitizer_allocator.cc ../../sanitizer_common/sanitizer_common.cc ../../sanitizer_common/sanitizer_deadlock_detector2.cc ../../sanitizer_common/sanitizer_flag_parser.cc ../../sanitizer_common/sanitizer_flags.cc ../../sanitizer_common/sanitizer_libc.cc ../../sanitizer_common/sanitizer_persistent_allocator.cc ../../sanitizer_common/sanitizer_printf.cc ../../sanitizer_common/sanitizer_suppressions.cc ../../sanitizer_common/sanitizer_thread_registry.cc ../../sanitizer_common/sanitizer_stackdepot.cc ../../sanitizer_common/sanitizer_stacktrace.cc ../../sanitizer_common/sanitizer_symbolizer.cc " if [ "`uname -a | grep Linux`" != "" ]; then SUFFIX="linux_amd64" OSCFLAGS="-fPIC -ffreestanding -Wno-maybe-uninitialized -Wno-unused-const-variable -Werror -Wno-unknown-warning-option" OSLDFLAGS="-lpthread -fPIC -fpie" SRCS=" $SRCS ../rtl/tsan_platform_linux.cc ../../sanitizer_common/sanitizer_posix.cc ../../sanitizer_common/sanitizer_posix_libcdep.cc ../../sanitizer_common/sanitizer_procmaps_common.cc ../../sanitizer_common/sanitizer_procmaps_linux.cc ../../sanitizer_common/sanitizer_linux.cc - ../../sanitizer_common/sanitizer_linux_libcdep.cc ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc " elif [ "`uname -a | grep FreeBSD`" != "" ]; then SUFFIX="freebsd_amd64" OSCFLAGS="-fno-strict-aliasing -fPIC -Werror" OSLDFLAGS="-lpthread -fPIC -fpie" SRCS=" $SRCS ../rtl/tsan_platform_linux.cc ../../sanitizer_common/sanitizer_posix.cc ../../sanitizer_common/sanitizer_posix_libcdep.cc ../../sanitizer_common/sanitizer_procmaps_common.cc ../../sanitizer_common/sanitizer_procmaps_freebsd.cc ../../sanitizer_common/sanitizer_linux.cc - ../../sanitizer_common/sanitizer_linux_libcdep.cc ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc " elif [ "`uname -a | grep Darwin`" != "" ]; then SUFFIX="darwin_amd64" OSCFLAGS="-fPIC -Wno-unused-const-variable -Wno-unknown-warning-option" OSLDFLAGS="-lpthread -fPIC -fpie" SRCS=" $SRCS ../rtl/tsan_platform_mac.cc ../../sanitizer_common/sanitizer_mac.cc ../../sanitizer_common/sanitizer_posix.cc ../../sanitizer_common/sanitizer_posix_libcdep.cc ../../sanitizer_common/sanitizer_procmaps_mac.cc " elif [ "`uname -a | grep MINGW`" != "" ]; then SUFFIX="windows_amd64" OSCFLAGS="-Wno-error=attributes -Wno-attributes -Wno-unused-const-variable -Wno-unknown-warning-option" OSLDFLAGS="" SRCS=" $SRCS ../rtl/tsan_platform_windows.cc ../../sanitizer_common/sanitizer_win.cc " else echo Unknown platform exit 1 fi CC=${CC:-gcc} IN_TMPDIR=${IN_TMPDIR:-0} SILENT=${SILENT:-0} if [ $IN_TMPDIR != "0" ]; then DIR=$(mktemp -qd /tmp/gotsan.XXXXXXXXXX) cleanup() { rm -rf $DIR } trap cleanup EXIT else DIR=. fi SRCS="$SRCS $ADD_SRCS" rm -f $DIR/gotsan.cc for F in $SRCS; do cat $F >> $DIR/gotsan.cc done FLAGS=" -I../rtl -I../.. -I../../sanitizer_common -I../../../include -std=c++11 -m64 -Wall -fno-exceptions -fno-rtti -DSANITIZER_GO -DSANITIZER_DEADLOCK_DETECTOR_VERSION=2 $OSCFLAGS" if [ "$DEBUG" = "" ]; then FLAGS="$FLAGS -DSANITIZER_DEBUG=0 -O3 -msse3 -fomit-frame-pointer" else FLAGS="$FLAGS -DSANITIZER_DEBUG=1 -g" fi if [ "$SILENT" != "1" ]; then echo $CC gotsan.cc -c -o $DIR/race_$SUFFIX.syso $FLAGS $CFLAGS fi $CC $DIR/gotsan.cc -c -o $DIR/race_$SUFFIX.syso $FLAGS $CFLAGS $CC test.c $DIR/race_$SUFFIX.syso -m64 -o $DIR/test $OSLDFLAGS export GORACE="exitcode=0 atexit_sleep_ms=0" if [ "$SILENT" != "1" ]; then $DIR/test else $DIR/test 2>/dev/null fi Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_defs.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_defs.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_defs.h (revision 279194) @@ -1,155 +1,162 @@ //===-- tsan_defs.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. // //===----------------------------------------------------------------------===// #ifndef TSAN_DEFS_H #define TSAN_DEFS_H #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_libc.h" #include "tsan_stat.h" +// Setup defaults for compile definitions. +#ifndef TSAN_NO_HISTORY +# define TSAN_NO_HISTORY 0 +#endif + +#ifndef TSAN_COLLECT_STATS +# define TSAN_COLLECT_STATS 0 +#endif + namespace __tsan { #ifdef SANITIZER_GO const bool kGoMode = true; const bool kCppMode = false; const char *const kTsanOptionsEnv = "GORACE"; // Go linker does not support weak symbols. #define CPP_WEAK #else const bool kGoMode = false; const bool kCppMode = true; const char *const kTsanOptionsEnv = "TSAN_OPTIONS"; #define CPP_WEAK WEAK #endif const int kTidBits = 13; const unsigned kMaxTid = 1 << kTidBits; +#ifndef SANITIZER_GO const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit. +#else +const unsigned kMaxTidInClock = kMaxTid; // Go does not track freed memory. +#endif const int kClkBits = 42; const unsigned kMaxTidReuse = (1 << (64 - kClkBits)) - 1; const uptr kShadowStackSize = 64 * 1024; // Count of shadow values in a shadow cell. const uptr kShadowCnt = 4; // That many user bytes are mapped onto a single shadow cell. const uptr kShadowCell = 8; // Size of a single shadow value (u64). const uptr kShadowSize = 8; // Shadow memory is kShadowMultiplier times larger than user memory. const uptr kShadowMultiplier = kShadowSize * kShadowCnt / kShadowCell; // That many user bytes are mapped onto a single meta shadow cell. // Must be less or equal to minimal memory allocator alignment. const uptr kMetaShadowCell = 8; // Size of a single meta shadow value (u32). const uptr kMetaShadowSize = 4; -#if defined(TSAN_NO_HISTORY) && TSAN_NO_HISTORY +#if TSAN_NO_HISTORY const bool kCollectHistory = false; #else const bool kCollectHistory = true; -#endif - -#if defined(TSAN_COLLECT_STATS) && TSAN_COLLECT_STATS -const bool kCollectStats = true; -#else -const bool kCollectStats = false; #endif // The following "build consistency" machinery ensures that all source files // are built in the same configuration. Inconsistent builds lead to // hard to debug crashes. #if SANITIZER_DEBUG void build_consistency_debug(); #else void build_consistency_release(); #endif #if TSAN_COLLECT_STATS void build_consistency_stats(); #else void build_consistency_nostats(); #endif static inline void USED build_consistency() { #if SANITIZER_DEBUG build_consistency_debug(); #else build_consistency_release(); #endif #if TSAN_COLLECT_STATS build_consistency_stats(); #else build_consistency_nostats(); #endif } template T min(T a, T b) { return a < b ? a : b; } template T max(T a, T b) { return a > b ? a : b; } template T RoundUp(T p, u64 align) { DCHECK_EQ(align & (align - 1), 0); return (T)(((u64)p + align - 1) & ~(align - 1)); } template T RoundDown(T p, u64 align) { DCHECK_EQ(align & (align - 1), 0); return (T)((u64)p & ~(align - 1)); } // Zeroizes high part, returns 'bits' lsb bits. template T GetLsb(T v, int bits) { return (T)((u64)v & ((1ull << bits) - 1)); } struct MD5Hash { u64 hash[2]; bool operator==(const MD5Hash &other) const; }; MD5Hash md5_hash(const void *data, uptr size); struct ThreadState; class ThreadContext; struct Context; struct ReportStack; class ReportDesc; class RegionAlloc; // Descriptor of user's memory block. struct MBlock { u64 siz; u32 stk; u16 tid; }; COMPILER_CHECK(sizeof(MBlock) == 16); } // namespace __tsan #endif // TSAN_DEFS_H Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.cc (revision 279194) @@ -1,102 +1,104 @@ //===-- tsan_flags.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 ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_libc.h" #include "tsan_flags.h" #include "tsan_rtl.h" #include "tsan_mman.h" namespace __tsan { Flags *flags() { return &ctx->flags; } // Can be overriden in frontend. #ifdef TSAN_EXTERNAL_HOOKS extern "C" const char* __tsan_default_options(); #else extern "C" SANITIZER_INTERFACE_ATTRIBUTE const char *WEAK __tsan_default_options() { return ""; } #endif void Flags::SetDefaults() { #define TSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; #include "tsan_flags.inc" #undef TSAN_FLAG // DDFlags second_deadlock_stack = false; } void RegisterTsanFlags(FlagParser *parser, Flags *f) { #define TSAN_FLAG(Type, Name, DefaultValue, Description) \ RegisterFlag(parser, #Name, Description, &f->Name); #include "tsan_flags.inc" #undef TSAN_FLAG } void InitializeFlags(Flags *f, const char *env) { FlagParser parser; RegisterTsanFlags(&parser, f); RegisterCommonFlags(&parser); f->SetDefaults(); SetCommonFlagsDefaults(); { // Override some common flags defaults. CommonFlags cf; cf.CopyFrom(*common_flags()); cf.allow_addr2line = true; +#ifndef SANITIZER_GO cf.detect_deadlocks = true; +#endif cf.print_suppressions = false; cf.stack_trace_format = " #%n %f %S %M"; OverrideCommonFlags(cf); } // Let a frontend override. parser.ParseString(__tsan_default_options()); // Override from command line. parser.ParseString(env); // Sanity check. if (!f->report_bugs) { f->report_thread_leaks = false; f->report_destroy_locked = false; f->report_signal_unsafe = false; } SetVerbosity(common_flags()->verbosity); if (Verbosity()) ReportUnrecognizedFlags(); if (common_flags()->help) parser.PrintFlagDescriptions(); if (f->history_size < 0 || f->history_size > 7) { Printf("ThreadSanitizer: incorrect value for history_size" " (must be [0..7])\n"); Die(); } if (f->io_sync < 0 || f->io_sync > 2) { Printf("ThreadSanitizer: incorrect value for io_sync" " (must be [0..2])\n"); Die(); } } } // namespace __tsan Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.inc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.inc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_flags.inc (revision 279194) @@ -1,78 +1,79 @@ //===-- tsan_flags.inc ------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // TSan runtime flags. // //===----------------------------------------------------------------------===// #ifndef TSAN_FLAG # error "Define TSAN_FLAG prior to including this file!" #endif // TSAN_FLAG(Type, Name, DefaultValue, Description) // See COMMON_FLAG in sanitizer_flags.inc for more details. TSAN_FLAG(bool, enable_annotations, true, "Enable dynamic annotations, otherwise they are no-ops.") // Suppress a race report if we've already output another race report // with the same stack. TSAN_FLAG(bool, suppress_equal_stacks, true, "Suppress a race report if we've already output another race report " "with the same stack.") TSAN_FLAG(bool, suppress_equal_addresses, true, "Suppress a race report if we've already output another race report " "on the same address.") TSAN_FLAG(bool, report_bugs, true, "Turns off bug reporting entirely (useful for benchmarking).") TSAN_FLAG(bool, report_thread_leaks, true, "Report thread leaks at exit?") TSAN_FLAG(bool, report_destroy_locked, true, "Report destruction of a locked mutex?") TSAN_FLAG(bool, report_mutex_bugs, true, "Report incorrect usages of mutexes and mutex annotations?") TSAN_FLAG(bool, report_signal_unsafe, true, "Report violations of async signal-safety " "(e.g. malloc() call from a signal handler).") TSAN_FLAG(bool, report_atomic_races, true, "Report races between atomic and plain memory accesses.") TSAN_FLAG( bool, force_seq_cst_atomics, false, "If set, all atomics are effectively sequentially consistent (seq_cst), " "regardless of what user actually specified.") TSAN_FLAG(bool, print_benign, false, "Print matched \"benign\" races at exit.") TSAN_FLAG(int, exitcode, 66, "Override exit status if something was reported.") TSAN_FLAG(bool, halt_on_error, false, "Exit after first reported error.") TSAN_FLAG(int, atexit_sleep_ms, 1000, "Sleep in main thread before exiting for that many ms " "(useful to catch \"at exit\" races).") TSAN_FLAG(const char *, profile_memory, "", "If set, periodically write memory profile to that file.") TSAN_FLAG(int, flush_memory_ms, 0, "Flush shadow memory every X ms.") TSAN_FLAG(int, flush_symbolizer_ms, 5000, "Flush symbolizer caches every X ms.") TSAN_FLAG( int, memory_limit_mb, 0, "Resident memory limit in MB to aim at." "If the process consumes more memory, then TSan will flush shadow memory.") TSAN_FLAG(bool, stop_on_start, false, "Stops on start until __tsan_resume() is called (for debugging).") TSAN_FLAG(bool, running_on_valgrind, false, "Controls whether RunningOnValgrind() returns true or false.") TSAN_FLAG( - int, history_size, kGoMode ? 1 : 2, // There are a lot of goroutines in Go. + int, history_size, kGoMode ? 1 : 3, // There are a lot of goroutines in Go. "Per-thread history size, controls how many previous memory accesses " "are remembered per thread. Possible values are [0..7]. " "history_size=0 amounts to 32K memory accesses. Each next value doubles " "the amount of memory accesses, up to history_size=7 that amounts to " "4M memory accesses. The default value is 2 (128K memory accesses).") TSAN_FLAG(int, io_sync, 1, "Controls level of synchronization implied by IO operations. " "0 - no synchronization " "1 - reasonable level of synchronization (write->read)" "2 - global synchronization of all IO operations.") TSAN_FLAG(bool, die_after_fork, true, "Die after multi-threaded fork if the child creates new threads.") +TSAN_FLAG(const char *, suppressions, "", "Suppressions file name.") Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc (revision 279194) @@ -1,2598 +1,2629 @@ //===-- tsan_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 ThreadSanitizer (TSan), a race detector. // // FIXME: move as many interceptors as possible into // sanitizer_common/sanitizer_common_interceptors.inc //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "interception/interception.h" #include "tsan_interface.h" #include "tsan_platform.h" #include "tsan_suppressions.h" #include "tsan_rtl.h" #include "tsan_mman.h" #include "tsan_fd.h" using namespace __tsan; // NOLINT #if SANITIZER_FREEBSD #define __errno_location __error #define __libc_malloc __malloc #define __libc_realloc __realloc #define __libc_calloc __calloc #define __libc_free __free #define stdout __stdoutp #define stderr __stderrp #endif +#ifdef __mips__ +const int kSigCount = 129; +#else const int kSigCount = 65; +#endif struct my_siginfo_t { // The size is determined by looking at sizeof of real siginfo_t on linux. u64 opaque[128 / sizeof(u64)]; }; +#ifdef __mips__ struct ucontext_t { + u64 opaque[768 / sizeof(u64) + 1]; +}; +#else +struct ucontext_t { // The size is determined by looking at sizeof of real ucontext_t on linux. u64 opaque[936 / sizeof(u64) + 1]; }; +#endif extern "C" int pthread_attr_init(void *attr); extern "C" int pthread_attr_destroy(void *attr); DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *) extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize); extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v)); extern "C" int pthread_setspecific(unsigned key, const void *v); DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *) extern "C" int pthread_yield(); extern "C" int pthread_sigmask(int how, const __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset); // REAL(sigfillset) defined in common interceptors. DECLARE_REAL(int, sigfillset, __sanitizer_sigset_t *set) DECLARE_REAL(int, fflush, __sanitizer_FILE *fp) extern "C" void *pthread_self(); extern "C" void _exit(int status); extern "C" int *__errno_location(); extern "C" int fileno_unlocked(void *stream); extern "C" void *__libc_malloc(uptr size); extern "C" void *__libc_calloc(uptr size, uptr n); extern "C" void *__libc_realloc(void *ptr, uptr size); extern "C" void __libc_free(void *ptr); extern "C" int dirfd(void *dirp); #if !SANITIZER_FREEBSD extern "C" int mallopt(int param, int value); #endif extern __sanitizer_FILE *stdout, *stderr; const int PTHREAD_MUTEX_RECURSIVE = 1; const int PTHREAD_MUTEX_RECURSIVE_NP = 1; const int EINVAL = 22; const int EBUSY = 16; const int EOWNERDEAD = 130; const int EPOLL_CTL_ADD = 1; const int SIGILL = 4; const int SIGABRT = 6; const int SIGFPE = 8; const int SIGSEGV = 11; const int SIGPIPE = 13; const int SIGTERM = 15; +#ifdef __mips__ +const int SIGBUS = 10; +const int SIGSYS = 12; +#else const int SIGBUS = 7; const int SIGSYS = 31; +#endif void *const MAP_FAILED = (void*)-1; const int PTHREAD_BARRIER_SERIAL_THREAD = -1; const int MAP_FIXED = 0x10; typedef long long_t; // NOLINT // From /usr/include/unistd.h # define F_ULOCK 0 /* Unlock a previously locked region. */ # define F_LOCK 1 /* Lock a region for exclusive use. */ # define F_TLOCK 2 /* Test and lock a region for exclusive use. */ # define F_TEST 3 /* Test a region for other processes locks. */ #define errno (*__errno_location()) typedef void (*sighandler_t)(int sig); typedef void (*sigactionhandler_t)(int sig, my_siginfo_t *siginfo, void *uctx); struct sigaction_t { +#ifdef __mips__ + u32 sa_flags; +#endif union { sighandler_t sa_handler; sigactionhandler_t sa_sigaction; }; #if SANITIZER_FREEBSD int sa_flags; __sanitizer_sigset_t sa_mask; #else __sanitizer_sigset_t sa_mask; +#ifndef __mips__ int sa_flags; +#endif void (*sa_restorer)(); #endif }; const sighandler_t SIG_DFL = (sighandler_t)0; const sighandler_t SIG_IGN = (sighandler_t)1; const sighandler_t SIG_ERR = (sighandler_t)-1; +#ifdef __mips__ +const int SA_SIGINFO = 8; +const int SIG_SETMASK = 3; +#else const int SA_SIGINFO = 4; const int SIG_SETMASK = 2; +#endif namespace std { struct nothrow_t {}; } // namespace std static sigaction_t sigactions[kSigCount]; namespace __tsan { struct SignalDesc { bool armed; bool sigaction; my_siginfo_t siginfo; ucontext_t ctx; }; struct SignalContext { int int_signal_send; atomic_uintptr_t in_blocking_func; atomic_uintptr_t have_pending_signals; SignalDesc pending_signals[kSigCount]; }; // The object is 64-byte aligned, because we want hot data to be located in // a single cache line if possible (it's accessed in every interceptor). static ALIGNED(64) char libignore_placeholder[sizeof(LibIgnore)]; static LibIgnore *libignore() { return reinterpret_cast(&libignore_placeholder[0]); } void InitializeLibIgnore() { - libignore()->Init(*SuppressionContext::Get()); + const SuppressionContext &supp = *Suppressions(); + const uptr n = supp.SuppressionCount(); + for (uptr i = 0; i < n; i++) { + const Suppression *s = supp.SuppressionAt(i); + if (0 == internal_strcmp(s->type, kSuppressionLib)) + libignore()->AddIgnoredLibrary(s->templ); + } libignore()->OnLibraryLoaded(0); } } // namespace __tsan static SignalContext *SigCtx(ThreadState *thr) { SignalContext *ctx = (SignalContext*)thr->signal_ctx; if (ctx == 0 && !thr->is_dead) { ctx = (SignalContext*)MmapOrDie(sizeof(*ctx), "SignalContext"); MemoryResetRange(thr, (uptr)&SigCtx, (uptr)ctx, sizeof(*ctx)); thr->signal_ctx = ctx; } return ctx; } static unsigned g_thread_finalize_key; class ScopedInterceptor { public: ScopedInterceptor(ThreadState *thr, const char *fname, uptr pc); ~ScopedInterceptor(); private: ThreadState *const thr_; const uptr pc_; bool in_ignored_lib_; }; ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname, uptr pc) : thr_(thr) , pc_(pc) , in_ignored_lib_(false) { if (!thr_->ignore_interceptors) { Initialize(thr); FuncEntry(thr, pc); } DPrintf("#%d: intercept %s()\n", thr_->tid, fname); if (!thr_->in_ignored_lib && libignore()->IsIgnored(pc)) { in_ignored_lib_ = true; thr_->in_ignored_lib = true; ThreadIgnoreBegin(thr_, pc_); } } ScopedInterceptor::~ScopedInterceptor() { if (in_ignored_lib_) { thr_->in_ignored_lib = false; ThreadIgnoreEnd(thr_, pc_); } if (!thr_->ignore_interceptors) { ProcessPendingSignals(thr_); FuncExit(thr_); CheckNoLocks(thr_); } } #define SCOPED_INTERCEPTOR_RAW(func, ...) \ ThreadState *thr = cur_thread(); \ const uptr caller_pc = GET_CALLER_PC(); \ ScopedInterceptor si(thr, #func, caller_pc); \ const uptr pc = StackTrace::GetCurrentPc(); \ (void)pc; \ /**/ #define SCOPED_TSAN_INTERCEPTOR(func, ...) \ SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \ if (REAL(func) == 0) { \ Report("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \ Die(); \ } \ if (thr->ignore_interceptors || thr->in_ignored_lib) \ return REAL(func)(__VA_ARGS__); \ /**/ #define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__) #define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func) #if SANITIZER_FREEBSD # define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func) #else # define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver) #endif #define BLOCK_REAL(name) (BlockingCall(thr), REAL(name)) struct BlockingCall { explicit BlockingCall(ThreadState *thr) : thr(thr) , ctx(SigCtx(thr)) { for (;;) { atomic_store(&ctx->in_blocking_func, 1, memory_order_relaxed); if (atomic_load(&ctx->have_pending_signals, memory_order_relaxed) == 0) break; atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed); ProcessPendingSignals(thr); } // When we are in a "blocking call", we process signals asynchronously // (right when they arrive). In this context we do not expect to be // executing any user/runtime code. The known interceptor sequence when // this is not true is: pthread_join -> munmap(stack). It's fine // to ignore munmap in this case -- we handle stack shadow separately. thr->ignore_interceptors++; } ~BlockingCall() { thr->ignore_interceptors--; atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed); } ThreadState *thr; SignalContext *ctx; }; TSAN_INTERCEPTOR(unsigned, sleep, unsigned sec) { SCOPED_TSAN_INTERCEPTOR(sleep, sec); unsigned res = BLOCK_REAL(sleep)(sec); AfterSleep(thr, pc); return res; } TSAN_INTERCEPTOR(int, usleep, long_t usec) { SCOPED_TSAN_INTERCEPTOR(usleep, usec); int res = BLOCK_REAL(usleep)(usec); AfterSleep(thr, pc); return res; } TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) { SCOPED_TSAN_INTERCEPTOR(nanosleep, req, rem); int res = BLOCK_REAL(nanosleep)(req, rem); AfterSleep(thr, pc); return res; } // The sole reason tsan wraps atexit callbacks is to establish synchronization // between callback setup and callback execution. struct AtExitCtx { void (*f)(); void *arg; }; static void at_exit_wrapper(void *arg) { ThreadState *thr = cur_thread(); uptr pc = 0; Acquire(thr, pc, (uptr)arg); AtExitCtx *ctx = (AtExitCtx*)arg; ((void(*)(void *arg))ctx->f)(ctx->arg); __libc_free(ctx); } static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(), void *arg, void *dso); TSAN_INTERCEPTOR(int, atexit, void (*f)()) { if (cur_thread()->in_symbolizer) return 0; // We want to setup the atexit callback even if we are in ignored lib // or after fork. SCOPED_INTERCEPTOR_RAW(atexit, f); return setup_at_exit_wrapper(thr, pc, (void(*)())f, 0, 0); } TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) { if (cur_thread()->in_symbolizer) return 0; SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso); return setup_at_exit_wrapper(thr, pc, (void(*)())f, arg, dso); } static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(), void *arg, void *dso) { AtExitCtx *ctx = (AtExitCtx*)__libc_malloc(sizeof(AtExitCtx)); ctx->f = f; ctx->arg = arg; Release(thr, pc, (uptr)ctx); // Memory allocation in __cxa_atexit will race with free during exit, // because we do not see synchronization around atexit callback list. ThreadIgnoreBegin(thr, pc); int res = REAL(__cxa_atexit)(at_exit_wrapper, ctx, dso); ThreadIgnoreEnd(thr, pc); return res; } static void on_exit_wrapper(int status, void *arg) { ThreadState *thr = cur_thread(); uptr pc = 0; Acquire(thr, pc, (uptr)arg); AtExitCtx *ctx = (AtExitCtx*)arg; ((void(*)(int status, void *arg))ctx->f)(status, ctx->arg); __libc_free(ctx); } TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) { if (cur_thread()->in_symbolizer) return 0; SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg); AtExitCtx *ctx = (AtExitCtx*)__libc_malloc(sizeof(AtExitCtx)); ctx->f = (void(*)())f; ctx->arg = arg; Release(thr, pc, (uptr)ctx); // Memory allocation in __cxa_atexit will race with free during exit, // because we do not see synchronization around atexit callback list. ThreadIgnoreBegin(thr, pc); int res = REAL(on_exit)(on_exit_wrapper, ctx); ThreadIgnoreEnd(thr, pc); return res; } // Cleanup old bufs. static void JmpBufGarbageCollect(ThreadState *thr, uptr sp) { for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) { JmpBuf *buf = &thr->jmp_bufs[i]; if (buf->sp <= sp) { uptr sz = thr->jmp_bufs.Size(); thr->jmp_bufs[i] = thr->jmp_bufs[sz - 1]; thr->jmp_bufs.PopBack(); i--; } } } static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) { if (thr->shadow_stack_pos == 0) // called from libc guts during bootstrap return; // Cleanup old bufs. JmpBufGarbageCollect(thr, sp); // Remember the buf. JmpBuf *buf = thr->jmp_bufs.PushBack(); buf->sp = sp; buf->mangled_sp = mangled_sp; buf->shadow_stack_pos = thr->shadow_stack_pos; SignalContext *sctx = SigCtx(thr); buf->int_signal_send = sctx ? sctx->int_signal_send : 0; buf->in_blocking_func = sctx ? atomic_load(&sctx->in_blocking_func, memory_order_relaxed) : false; buf->in_signal_handler = atomic_load(&thr->in_signal_handler, memory_order_relaxed); } static void LongJmp(ThreadState *thr, uptr *env) { #if SANITIZER_FREEBSD uptr mangled_sp = env[2]; #else uptr mangled_sp = env[6]; #endif // SANITIZER_FREEBSD // Find the saved buf by mangled_sp. for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) { JmpBuf *buf = &thr->jmp_bufs[i]; if (buf->mangled_sp == mangled_sp) { CHECK_GE(thr->shadow_stack_pos, buf->shadow_stack_pos); // Unwind the stack. while (thr->shadow_stack_pos > buf->shadow_stack_pos) FuncExit(thr); SignalContext *sctx = SigCtx(thr); if (sctx) { sctx->int_signal_send = buf->int_signal_send; atomic_store(&sctx->in_blocking_func, buf->in_blocking_func, memory_order_relaxed); } atomic_store(&thr->in_signal_handler, buf->in_signal_handler, memory_order_relaxed); JmpBufGarbageCollect(thr, buf->sp - 1); // do not collect buf->sp return; } } Printf("ThreadSanitizer: can't find longjmp buf\n"); CHECK(0); } // FIXME: put everything below into a common extern "C" block? extern "C" void __tsan_setjmp(uptr sp, uptr mangled_sp) { SetJmp(cur_thread(), sp, mangled_sp); } // Not called. Merely to satisfy TSAN_INTERCEPT(). extern "C" SANITIZER_INTERFACE_ATTRIBUTE int __interceptor_setjmp(void *env); extern "C" int __interceptor_setjmp(void *env) { CHECK(0); return 0; } // FIXME: any reason to have a separate declaration? extern "C" SANITIZER_INTERFACE_ATTRIBUTE int __interceptor__setjmp(void *env); extern "C" int __interceptor__setjmp(void *env) { CHECK(0); return 0; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE int __interceptor_sigsetjmp(void *env); extern "C" int __interceptor_sigsetjmp(void *env) { CHECK(0); return 0; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE int __interceptor___sigsetjmp(void *env); extern "C" int __interceptor___sigsetjmp(void *env) { CHECK(0); return 0; } extern "C" int setjmp(void *env); extern "C" int _setjmp(void *env); extern "C" int sigsetjmp(void *env); extern "C" int __sigsetjmp(void *env); DEFINE_REAL(int, setjmp, void *env) DEFINE_REAL(int, _setjmp, void *env) DEFINE_REAL(int, sigsetjmp, void *env) DEFINE_REAL(int, __sigsetjmp, void *env) TSAN_INTERCEPTOR(void, longjmp, uptr *env, int val) { { SCOPED_TSAN_INTERCEPTOR(longjmp, env, val); } LongJmp(cur_thread(), env); REAL(longjmp)(env, val); } TSAN_INTERCEPTOR(void, siglongjmp, uptr *env, int val) { { SCOPED_TSAN_INTERCEPTOR(siglongjmp, env, val); } LongJmp(cur_thread(), env); REAL(siglongjmp)(env, val); } TSAN_INTERCEPTOR(void*, malloc, uptr size) { if (cur_thread()->in_symbolizer) return __libc_malloc(size); void *p = 0; { SCOPED_INTERCEPTOR_RAW(malloc, size); p = user_alloc(thr, pc, size); } invoke_malloc_hook(p, size); return p; } TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) { SCOPED_TSAN_INTERCEPTOR(__libc_memalign, align, sz); return user_alloc(thr, pc, sz, align); } TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) { if (cur_thread()->in_symbolizer) return __libc_calloc(size, n); void *p = 0; { SCOPED_INTERCEPTOR_RAW(calloc, size, n); p = user_calloc(thr, pc, size, n); } invoke_malloc_hook(p, n * size); return p; } TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) { if (cur_thread()->in_symbolizer) return __libc_realloc(p, size); if (p) invoke_free_hook(p); { SCOPED_INTERCEPTOR_RAW(realloc, p, size); p = user_realloc(thr, pc, p, size); } invoke_malloc_hook(p, size); return p; } TSAN_INTERCEPTOR(void, free, void *p) { if (p == 0) return; if (cur_thread()->in_symbolizer) return __libc_free(p); invoke_free_hook(p); SCOPED_INTERCEPTOR_RAW(free, p); user_free(thr, pc, p); } TSAN_INTERCEPTOR(void, cfree, void *p) { if (p == 0) return; if (cur_thread()->in_symbolizer) return __libc_free(p); invoke_free_hook(p); SCOPED_INTERCEPTOR_RAW(cfree, p); user_free(thr, pc, p); } TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) { SCOPED_INTERCEPTOR_RAW(malloc_usable_size, p); return user_alloc_usable_size(p); } #define OPERATOR_NEW_BODY(mangled_name) \ if (cur_thread()->in_symbolizer) \ return __libc_malloc(size); \ void *p = 0; \ { \ SCOPED_INTERCEPTOR_RAW(mangled_name, size); \ p = user_alloc(thr, pc, size); \ } \ invoke_malloc_hook(p, size); \ return p; SANITIZER_INTERFACE_ATTRIBUTE void *operator new(__sanitizer::uptr size); void *operator new(__sanitizer::uptr size) { OPERATOR_NEW_BODY(_Znwm); } SANITIZER_INTERFACE_ATTRIBUTE void *operator new[](__sanitizer::uptr size); void *operator new[](__sanitizer::uptr size) { OPERATOR_NEW_BODY(_Znam); } SANITIZER_INTERFACE_ATTRIBUTE void *operator new(__sanitizer::uptr size, std::nothrow_t const&); void *operator new(__sanitizer::uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t); } SANITIZER_INTERFACE_ATTRIBUTE void *operator new[](__sanitizer::uptr size, std::nothrow_t const&); void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t); } #define OPERATOR_DELETE_BODY(mangled_name) \ if (ptr == 0) return; \ if (cur_thread()->in_symbolizer) \ return __libc_free(ptr); \ invoke_free_hook(ptr); \ SCOPED_INTERCEPTOR_RAW(mangled_name, ptr); \ user_free(thr, pc, ptr); SANITIZER_INTERFACE_ATTRIBUTE void operator delete(void *ptr) throw(); void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY(_ZdlPv); } SANITIZER_INTERFACE_ATTRIBUTE void operator delete[](void *ptr) throw(); void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY(_ZdaPv); } SANITIZER_INTERFACE_ATTRIBUTE void operator delete(void *ptr, std::nothrow_t const&); void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY(_ZdlPvRKSt9nothrow_t); } SANITIZER_INTERFACE_ATTRIBUTE void operator delete[](void *ptr, std::nothrow_t const&); void operator delete[](void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY(_ZdaPvRKSt9nothrow_t); } TSAN_INTERCEPTOR(uptr, strlen, const char *s) { SCOPED_TSAN_INTERCEPTOR(strlen, s); uptr len = internal_strlen(s); MemoryAccessRange(thr, pc, (uptr)s, len + 1, false); return len; } TSAN_INTERCEPTOR(void*, memset, void *dst, int v, uptr size) { SCOPED_TSAN_INTERCEPTOR(memset, dst, v, size); MemoryAccessRange(thr, pc, (uptr)dst, size, true); return internal_memset(dst, v, size); } TSAN_INTERCEPTOR(void*, memcpy, void *dst, const void *src, uptr size) { SCOPED_TSAN_INTERCEPTOR(memcpy, dst, src, size); MemoryAccessRange(thr, pc, (uptr)dst, size, true); MemoryAccessRange(thr, pc, (uptr)src, size, false); return internal_memcpy(dst, src, size); } TSAN_INTERCEPTOR(int, memcmp, const void *s1, const void *s2, uptr n) { SCOPED_TSAN_INTERCEPTOR(memcmp, s1, s2, n); int res = 0; uptr len = 0; for (; len < n; len++) { if ((res = ((const unsigned char *)s1)[len] - ((const unsigned char *)s2)[len])) break; } MemoryAccessRange(thr, pc, (uptr)s1, len < n ? len + 1 : n, false); MemoryAccessRange(thr, pc, (uptr)s2, len < n ? len + 1 : n, false); return res; } TSAN_INTERCEPTOR(void*, memmove, void *dst, void *src, uptr n) { SCOPED_TSAN_INTERCEPTOR(memmove, dst, src, n); MemoryAccessRange(thr, pc, (uptr)dst, n, true); MemoryAccessRange(thr, pc, (uptr)src, n, false); return REAL(memmove)(dst, src, n); } TSAN_INTERCEPTOR(char*, strchr, char *s, int c) { SCOPED_TSAN_INTERCEPTOR(strchr, s, c); char *res = REAL(strchr)(s, c); uptr len = res ? (char*)res - (char*)s + 1 : internal_strlen(s) + 1; MemoryAccessRange(thr, pc, (uptr)s, len, false); return res; } TSAN_INTERCEPTOR(char*, strchrnul, char *s, int c) { SCOPED_TSAN_INTERCEPTOR(strchrnul, s, c); char *res = REAL(strchrnul)(s, c); uptr len = (char*)res - (char*)s + 1; MemoryAccessRange(thr, pc, (uptr)s, len, false); return res; } TSAN_INTERCEPTOR(char*, strrchr, char *s, int c) { SCOPED_TSAN_INTERCEPTOR(strrchr, s, c); MemoryAccessRange(thr, pc, (uptr)s, internal_strlen(s) + 1, false); return REAL(strrchr)(s, c); } TSAN_INTERCEPTOR(char*, strcpy, char *dst, const char *src) { // NOLINT SCOPED_TSAN_INTERCEPTOR(strcpy, dst, src); // NOLINT uptr srclen = internal_strlen(src); MemoryAccessRange(thr, pc, (uptr)dst, srclen + 1, true); MemoryAccessRange(thr, pc, (uptr)src, srclen + 1, false); return REAL(strcpy)(dst, src); // NOLINT } TSAN_INTERCEPTOR(char*, strncpy, char *dst, char *src, uptr n) { SCOPED_TSAN_INTERCEPTOR(strncpy, dst, src, n); uptr srclen = internal_strnlen(src, n); MemoryAccessRange(thr, pc, (uptr)dst, n, true); MemoryAccessRange(thr, pc, (uptr)src, min(srclen + 1, n), false); return REAL(strncpy)(dst, src, n); } TSAN_INTERCEPTOR(const char*, strstr, const char *s1, const char *s2) { SCOPED_TSAN_INTERCEPTOR(strstr, s1, s2); const char *res = REAL(strstr)(s1, s2); uptr len1 = internal_strlen(s1); uptr len2 = internal_strlen(s2); MemoryAccessRange(thr, pc, (uptr)s1, len1 + 1, false); MemoryAccessRange(thr, pc, (uptr)s2, len2 + 1, false); return res; } TSAN_INTERCEPTOR(char*, strdup, const char *str) { SCOPED_TSAN_INTERCEPTOR(strdup, str); // strdup will call malloc, so no instrumentation is required here. return REAL(strdup)(str); } static bool fix_mmap_addr(void **addr, long_t sz, int flags) { if (*addr) { if (!IsAppMem((uptr)*addr) || !IsAppMem((uptr)*addr + sz - 1)) { if (flags & MAP_FIXED) { errno = EINVAL; return false; } else { *addr = 0; } } } return true; } TSAN_INTERCEPTOR(void*, mmap, void *addr, long_t sz, int prot, int flags, int fd, unsigned off) { SCOPED_TSAN_INTERCEPTOR(mmap, addr, sz, prot, flags, fd, off); if (!fix_mmap_addr(&addr, sz, flags)) return MAP_FAILED; void *res = REAL(mmap)(addr, sz, prot, flags, fd, off); if (res != MAP_FAILED) { if (fd > 0) FdAccess(thr, pc, fd); MemoryRangeImitateWrite(thr, pc, (uptr)res, sz); } return res; } #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(void*, mmap64, void *addr, long_t sz, int prot, int flags, int fd, u64 off) { SCOPED_TSAN_INTERCEPTOR(mmap64, addr, sz, prot, flags, fd, off); if (!fix_mmap_addr(&addr, sz, flags)) return MAP_FAILED; void *res = REAL(mmap64)(addr, sz, prot, flags, fd, off); if (res != MAP_FAILED) { if (fd > 0) FdAccess(thr, pc, fd); MemoryRangeImitateWrite(thr, pc, (uptr)res, sz); } return res; } #define TSAN_MAYBE_INTERCEPT_MMAP64 TSAN_INTERCEPT(mmap64) #else #define TSAN_MAYBE_INTERCEPT_MMAP64 #endif TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) { SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz); DontNeedShadowFor((uptr)addr, sz); int res = REAL(munmap)(addr, sz); return res; } #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) { SCOPED_INTERCEPTOR_RAW(memalign, align, sz); return user_alloc(thr, pc, sz, align); } #define TSAN_MAYBE_INTERCEPT_MEMALIGN TSAN_INTERCEPT(memalign) #else #define TSAN_MAYBE_INTERCEPT_MEMALIGN #endif TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) { SCOPED_INTERCEPTOR_RAW(memalign, align, sz); return user_alloc(thr, pc, sz, align); } TSAN_INTERCEPTOR(void*, valloc, uptr sz) { SCOPED_INTERCEPTOR_RAW(valloc, sz); return user_alloc(thr, pc, sz, GetPageSizeCached()); } #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) { SCOPED_INTERCEPTOR_RAW(pvalloc, sz); sz = RoundUp(sz, GetPageSizeCached()); return user_alloc(thr, pc, sz, GetPageSizeCached()); } #define TSAN_MAYBE_INTERCEPT_PVALLOC TSAN_INTERCEPT(pvalloc) #else #define TSAN_MAYBE_INTERCEPT_PVALLOC #endif TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) { SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz); *memptr = user_alloc(thr, pc, sz, align); return 0; } // Used in thread-safe function static initialization. extern "C" int INTERFACE_ATTRIBUTE __cxa_guard_acquire(atomic_uint32_t *g) { SCOPED_INTERCEPTOR_RAW(__cxa_guard_acquire, g); for (;;) { u32 cmp = atomic_load(g, memory_order_acquire); if (cmp == 0) { if (atomic_compare_exchange_strong(g, &cmp, 1<<16, memory_order_relaxed)) return 1; } else if (cmp == 1) { Acquire(thr, pc, (uptr)g); return 0; } else { internal_sched_yield(); } } } extern "C" void INTERFACE_ATTRIBUTE __cxa_guard_release(atomic_uint32_t *g) { SCOPED_INTERCEPTOR_RAW(__cxa_guard_release, g); Release(thr, pc, (uptr)g); atomic_store(g, 1, memory_order_release); } extern "C" void INTERFACE_ATTRIBUTE __cxa_guard_abort(atomic_uint32_t *g) { SCOPED_INTERCEPTOR_RAW(__cxa_guard_abort, g); atomic_store(g, 0, memory_order_relaxed); } static void thread_finalize(void *v) { uptr iter = (uptr)v; if (iter > 1) { if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) { Printf("ThreadSanitizer: failed to set thread key\n"); Die(); } return; } { ThreadState *thr = cur_thread(); ThreadFinish(thr); SignalContext *sctx = thr->signal_ctx; if (sctx) { thr->signal_ctx = 0; UnmapOrDie(sctx, sizeof(*sctx)); } } } struct ThreadParam { void* (*callback)(void *arg); void *param; atomic_uintptr_t tid; }; extern "C" void *__tsan_thread_start_func(void *arg) { ThreadParam *p = (ThreadParam*)arg; void* (*callback)(void *arg) = p->callback; void *param = p->param; int tid = 0; { ThreadState *thr = cur_thread(); // Thread-local state is not initialized yet. ScopedIgnoreInterceptors ignore; ThreadIgnoreBegin(thr, 0); if (pthread_setspecific(g_thread_finalize_key, (void *)kPthreadDestructorIterations)) { Printf("ThreadSanitizer: failed to set thread key\n"); Die(); } ThreadIgnoreEnd(thr, 0); while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) pthread_yield(); atomic_store(&p->tid, 0, memory_order_release); ThreadStart(thr, tid, GetTid()); } void *res = callback(param); // Prevent the callback from being tail called, // it mixes up stack traces. volatile int foo = 42; foo++; return res; } TSAN_INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*), void * param) { SCOPED_INTERCEPTOR_RAW(pthread_create, th, attr, callback, param); if (ctx->after_multithreaded_fork) { if (flags()->die_after_fork) { Report("ThreadSanitizer: starting new threads after multi-threaded " "fork is not supported. Dying (set die_after_fork=0 to override)\n"); Die(); } else { VPrintf(1, "ThreadSanitizer: starting new threads after multi-threaded " "fork is not supported (pid %d). Continuing because of " "die_after_fork=0, but you are on your own\n", internal_getpid()); } } __sanitizer_pthread_attr_t myattr; if (attr == 0) { pthread_attr_init(&myattr); attr = &myattr; } int detached = 0; REAL(pthread_attr_getdetachstate)(attr, &detached); AdjustStackSize(attr); ThreadParam p; p.callback = callback; p.param = param; atomic_store(&p.tid, 0, memory_order_relaxed); int res = -1; { // Otherwise we see false positives in pthread stack manipulation. ScopedIgnoreInterceptors ignore; ThreadIgnoreBegin(thr, pc); res = REAL(pthread_create)(th, attr, __tsan_thread_start_func, &p); ThreadIgnoreEnd(thr, pc); } if (res == 0) { int tid = ThreadCreate(thr, pc, *(uptr*)th, detached); CHECK_NE(tid, 0); atomic_store(&p.tid, tid, memory_order_release); while (atomic_load(&p.tid, memory_order_acquire) != 0) pthread_yield(); } if (attr == &myattr) pthread_attr_destroy(&myattr); return res; } TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) { SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret); int tid = ThreadTid(thr, pc, (uptr)th); ThreadIgnoreBegin(thr, pc); int res = BLOCK_REAL(pthread_join)(th, ret); ThreadIgnoreEnd(thr, pc); if (res == 0) { ThreadJoin(thr, pc, tid); } return res; } DEFINE_REAL_PTHREAD_FUNCTIONS TSAN_INTERCEPTOR(int, pthread_detach, void *th) { SCOPED_TSAN_INTERCEPTOR(pthread_detach, th); int tid = ThreadTid(thr, pc, (uptr)th); int res = REAL(pthread_detach)(th); if (res == 0) { ThreadDetach(thr, pc, tid); } return res; } // Problem: // NPTL implementation of pthread_cond has 2 versions (2.2.5 and 2.3.2). // pthread_cond_t has different size in the different versions. // If call new REAL functions for old pthread_cond_t, they will corrupt memory // after pthread_cond_t (old cond is smaller). // If we call old REAL functions for new pthread_cond_t, we will lose some // functionality (e.g. old functions do not support waiting against // CLOCK_REALTIME). // Proper handling would require to have 2 versions of interceptors as well. // But this is messy, in particular requires linker scripts when sanitizer // runtime is linked into a shared library. // Instead we assume we don't have dynamic libraries built against old // pthread (2.2.5 is dated by 2002). And provide legacy_pthread_cond flag // that allows to work with old libraries (but this mode does not support // some features, e.g. pthread_condattr_getpshared). static void *init_cond(void *c, bool force = false) { // sizeof(pthread_cond_t) >= sizeof(uptr) in both versions. // So we allocate additional memory on the side large enough to hold // any pthread_cond_t object. Always call new REAL functions, but pass // the aux object to them. // Note: the code assumes that PTHREAD_COND_INITIALIZER initializes // first word of pthread_cond_t to zero. // It's all relevant only for linux. if (!common_flags()->legacy_pthread_cond) return c; atomic_uintptr_t *p = (atomic_uintptr_t*)c; uptr cond = atomic_load(p, memory_order_acquire); if (!force && cond != 0) return (void*)cond; void *newcond = WRAP(malloc)(pthread_cond_t_sz); internal_memset(newcond, 0, pthread_cond_t_sz); if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond, memory_order_acq_rel)) return newcond; WRAP(free)(newcond); return (void*)cond; } struct CondMutexUnlockCtx { ThreadState *thr; uptr pc; void *m; }; static void cond_mutex_unlock(CondMutexUnlockCtx *arg) { MutexLock(arg->thr, arg->pc, (uptr)arg->m); } INTERCEPTOR(int, pthread_cond_init, void *c, void *a) { void *cond = init_cond(c, true); SCOPED_TSAN_INTERCEPTOR(pthread_cond_init, cond, a); MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true); return REAL(pthread_cond_init)(cond, a); } INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) { void *cond = init_cond(c); SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m); MutexUnlock(thr, pc, (uptr)m); MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false); CondMutexUnlockCtx arg = {thr, pc, m}; // This ensures that we handle mutex lock even in case of pthread_cancel. // See test/tsan/cond_cancel.cc. int res = call_pthread_cancel_with_cleanup( (int(*)(void *c, void *m, void *abstime))REAL(pthread_cond_wait), cond, m, 0, (void(*)(void *arg))cond_mutex_unlock, &arg); if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m); MutexLock(thr, pc, (uptr)m); return res; } INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) { void *cond = init_cond(c); SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime); MutexUnlock(thr, pc, (uptr)m); MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false); CondMutexUnlockCtx arg = {thr, pc, m}; // This ensures that we handle mutex lock even in case of pthread_cancel. // See test/tsan/cond_cancel.cc. int res = call_pthread_cancel_with_cleanup( REAL(pthread_cond_timedwait), cond, m, abstime, (void(*)(void *arg))cond_mutex_unlock, &arg); if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m); MutexLock(thr, pc, (uptr)m); return res; } INTERCEPTOR(int, pthread_cond_signal, void *c) { void *cond = init_cond(c); SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal, cond); MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false); return REAL(pthread_cond_signal)(cond); } INTERCEPTOR(int, pthread_cond_broadcast, void *c) { void *cond = init_cond(c); SCOPED_TSAN_INTERCEPTOR(pthread_cond_broadcast, cond); MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false); return REAL(pthread_cond_broadcast)(cond); } INTERCEPTOR(int, pthread_cond_destroy, void *c) { void *cond = init_cond(c); SCOPED_TSAN_INTERCEPTOR(pthread_cond_destroy, cond); MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true); int res = REAL(pthread_cond_destroy)(cond); if (common_flags()->legacy_pthread_cond) { // Free our aux cond and zero the pointer to not leave dangling pointers. WRAP(free)(cond); atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed); } return res; } TSAN_INTERCEPTOR(int, pthread_mutex_init, void *m, void *a) { SCOPED_TSAN_INTERCEPTOR(pthread_mutex_init, m, a); int res = REAL(pthread_mutex_init)(m, a); if (res == 0) { bool recursive = false; if (a) { int type = 0; if (REAL(pthread_mutexattr_gettype)(a, &type) == 0) recursive = (type == PTHREAD_MUTEX_RECURSIVE || type == PTHREAD_MUTEX_RECURSIVE_NP); } MutexCreate(thr, pc, (uptr)m, false, recursive, false); } return res; } TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_mutex_destroy, m); int res = REAL(pthread_mutex_destroy)(m); if (res == 0 || res == EBUSY) { MutexDestroy(thr, pc, (uptr)m); } return res; } TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_mutex_trylock, m); int res = REAL(pthread_mutex_trylock)(m); if (res == EOWNERDEAD) MutexRepair(thr, pc, (uptr)m); if (res == 0 || res == EOWNERDEAD) MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true); return res; } TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) { SCOPED_TSAN_INTERCEPTOR(pthread_mutex_timedlock, m, abstime); int res = REAL(pthread_mutex_timedlock)(m, abstime); if (res == 0) { MutexLock(thr, pc, (uptr)m); } return res; } TSAN_INTERCEPTOR(int, pthread_spin_init, void *m, int pshared) { SCOPED_TSAN_INTERCEPTOR(pthread_spin_init, m, pshared); int res = REAL(pthread_spin_init)(m, pshared); if (res == 0) { MutexCreate(thr, pc, (uptr)m, false, false, false); } return res; } TSAN_INTERCEPTOR(int, pthread_spin_destroy, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_spin_destroy, m); int res = REAL(pthread_spin_destroy)(m); if (res == 0) { MutexDestroy(thr, pc, (uptr)m); } return res; } TSAN_INTERCEPTOR(int, pthread_spin_lock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_spin_lock, m); int res = REAL(pthread_spin_lock)(m); if (res == 0) { MutexLock(thr, pc, (uptr)m); } return res; } TSAN_INTERCEPTOR(int, pthread_spin_trylock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_spin_trylock, m); int res = REAL(pthread_spin_trylock)(m); if (res == 0) { MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true); } return res; } TSAN_INTERCEPTOR(int, pthread_spin_unlock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_spin_unlock, m); MutexUnlock(thr, pc, (uptr)m); int res = REAL(pthread_spin_unlock)(m); return res; } TSAN_INTERCEPTOR(int, pthread_rwlock_init, void *m, void *a) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_init, m, a); int res = REAL(pthread_rwlock_init)(m, a); if (res == 0) { MutexCreate(thr, pc, (uptr)m, true, false, false); } return res; } TSAN_INTERCEPTOR(int, pthread_rwlock_destroy, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_destroy, m); int res = REAL(pthread_rwlock_destroy)(m); if (res == 0) { MutexDestroy(thr, pc, (uptr)m); } return res; } TSAN_INTERCEPTOR(int, pthread_rwlock_rdlock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_rdlock, m); int res = REAL(pthread_rwlock_rdlock)(m); if (res == 0) { MutexReadLock(thr, pc, (uptr)m); } return res; } TSAN_INTERCEPTOR(int, pthread_rwlock_tryrdlock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_tryrdlock, m); int res = REAL(pthread_rwlock_tryrdlock)(m); if (res == 0) { MutexReadLock(thr, pc, (uptr)m, /*try_lock=*/true); } return res; } TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedrdlock, m, abstime); int res = REAL(pthread_rwlock_timedrdlock)(m, abstime); if (res == 0) { MutexReadLock(thr, pc, (uptr)m); } return res; } TSAN_INTERCEPTOR(int, pthread_rwlock_wrlock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_wrlock, m); int res = REAL(pthread_rwlock_wrlock)(m); if (res == 0) { MutexLock(thr, pc, (uptr)m); } return res; } TSAN_INTERCEPTOR(int, pthread_rwlock_trywrlock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_trywrlock, m); int res = REAL(pthread_rwlock_trywrlock)(m); if (res == 0) { MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true); } return res; } TSAN_INTERCEPTOR(int, pthread_rwlock_timedwrlock, void *m, void *abstime) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedwrlock, m, abstime); int res = REAL(pthread_rwlock_timedwrlock)(m, abstime); if (res == 0) { MutexLock(thr, pc, (uptr)m); } return res; } TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) { SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_unlock, m); MutexReadOrWriteUnlock(thr, pc, (uptr)m); int res = REAL(pthread_rwlock_unlock)(m); return res; } TSAN_INTERCEPTOR(int, pthread_barrier_init, void *b, void *a, unsigned count) { SCOPED_TSAN_INTERCEPTOR(pthread_barrier_init, b, a, count); MemoryWrite(thr, pc, (uptr)b, kSizeLog1); int res = REAL(pthread_barrier_init)(b, a, count); return res; } TSAN_INTERCEPTOR(int, pthread_barrier_destroy, void *b) { SCOPED_TSAN_INTERCEPTOR(pthread_barrier_destroy, b); MemoryWrite(thr, pc, (uptr)b, kSizeLog1); int res = REAL(pthread_barrier_destroy)(b); return res; } TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) { SCOPED_TSAN_INTERCEPTOR(pthread_barrier_wait, b); Release(thr, pc, (uptr)b); MemoryRead(thr, pc, (uptr)b, kSizeLog1); int res = REAL(pthread_barrier_wait)(b); MemoryRead(thr, pc, (uptr)b, kSizeLog1); if (res == 0 || res == PTHREAD_BARRIER_SERIAL_THREAD) { Acquire(thr, pc, (uptr)b); } return res; } TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) { SCOPED_INTERCEPTOR_RAW(pthread_once, o, f); if (o == 0 || f == 0) return EINVAL; atomic_uint32_t *a = static_cast(o); u32 v = atomic_load(a, memory_order_acquire); if (v == 0 && atomic_compare_exchange_strong(a, &v, 1, memory_order_relaxed)) { (*f)(); if (!thr->in_ignored_lib) Release(thr, pc, (uptr)o); atomic_store(a, 2, memory_order_release); } else { while (v != 2) { pthread_yield(); v = atomic_load(a, memory_order_acquire); } if (!thr->in_ignored_lib) Acquire(thr, pc, (uptr)o); } return 0; } TSAN_INTERCEPTOR(int, sem_init, void *s, int pshared, unsigned value) { SCOPED_TSAN_INTERCEPTOR(sem_init, s, pshared, value); int res = REAL(sem_init)(s, pshared, value); return res; } TSAN_INTERCEPTOR(int, sem_destroy, void *s) { SCOPED_TSAN_INTERCEPTOR(sem_destroy, s); int res = REAL(sem_destroy)(s); return res; } TSAN_INTERCEPTOR(int, sem_wait, void *s) { SCOPED_TSAN_INTERCEPTOR(sem_wait, s); int res = BLOCK_REAL(sem_wait)(s); if (res == 0) { Acquire(thr, pc, (uptr)s); } return res; } TSAN_INTERCEPTOR(int, sem_trywait, void *s) { SCOPED_TSAN_INTERCEPTOR(sem_trywait, s); int res = BLOCK_REAL(sem_trywait)(s); if (res == 0) { Acquire(thr, pc, (uptr)s); } return res; } TSAN_INTERCEPTOR(int, sem_timedwait, void *s, void *abstime) { SCOPED_TSAN_INTERCEPTOR(sem_timedwait, s, abstime); int res = BLOCK_REAL(sem_timedwait)(s, abstime); if (res == 0) { Acquire(thr, pc, (uptr)s); } return res; } TSAN_INTERCEPTOR(int, sem_post, void *s) { SCOPED_TSAN_INTERCEPTOR(sem_post, s); Release(thr, pc, (uptr)s); int res = REAL(sem_post)(s); return res; } TSAN_INTERCEPTOR(int, sem_getvalue, void *s, int *sval) { SCOPED_TSAN_INTERCEPTOR(sem_getvalue, s, sval); int res = REAL(sem_getvalue)(s, sval); if (res == 0) { Acquire(thr, pc, (uptr)s); } return res; } #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) { SCOPED_TSAN_INTERCEPTOR(__xstat, version, path, buf); return REAL(__xstat)(version, path, buf); } #define TSAN_MAYBE_INTERCEPT___XSTAT TSAN_INTERCEPT(__xstat) #else #define TSAN_MAYBE_INTERCEPT___XSTAT #endif TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) { #if SANITIZER_FREEBSD SCOPED_TSAN_INTERCEPTOR(stat, path, buf); return REAL(stat)(path, buf); #else SCOPED_TSAN_INTERCEPTOR(__xstat, 0, path, buf); return REAL(__xstat)(0, path, buf); #endif } #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) { SCOPED_TSAN_INTERCEPTOR(__xstat64, version, path, buf); return REAL(__xstat64)(version, path, buf); } #define TSAN_MAYBE_INTERCEPT___XSTAT64 TSAN_INTERCEPT(__xstat64) #else #define TSAN_MAYBE_INTERCEPT___XSTAT64 #endif #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) { SCOPED_TSAN_INTERCEPTOR(__xstat64, 0, path, buf); return REAL(__xstat64)(0, path, buf); } #define TSAN_MAYBE_INTERCEPT_STAT64 TSAN_INTERCEPT(stat64) #else #define TSAN_MAYBE_INTERCEPT_STAT64 #endif #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) { SCOPED_TSAN_INTERCEPTOR(__lxstat, version, path, buf); return REAL(__lxstat)(version, path, buf); } #define TSAN_MAYBE_INTERCEPT___LXSTAT TSAN_INTERCEPT(__lxstat) #else #define TSAN_MAYBE_INTERCEPT___LXSTAT #endif TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) { #if SANITIZER_FREEBSD SCOPED_TSAN_INTERCEPTOR(lstat, path, buf); return REAL(lstat)(path, buf); #else SCOPED_TSAN_INTERCEPTOR(__lxstat, 0, path, buf); return REAL(__lxstat)(0, path, buf); #endif } #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) { SCOPED_TSAN_INTERCEPTOR(__lxstat64, version, path, buf); return REAL(__lxstat64)(version, path, buf); } #define TSAN_MAYBE_INTERCEPT___LXSTAT64 TSAN_INTERCEPT(__lxstat64) #else #define TSAN_MAYBE_INTERCEPT___LXSTAT64 #endif #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) { SCOPED_TSAN_INTERCEPTOR(__lxstat64, 0, path, buf); return REAL(__lxstat64)(0, path, buf); } #define TSAN_MAYBE_INTERCEPT_LSTAT64 TSAN_INTERCEPT(lstat64) #else #define TSAN_MAYBE_INTERCEPT_LSTAT64 #endif #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) { SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf); if (fd > 0) FdAccess(thr, pc, fd); return REAL(__fxstat)(version, fd, buf); } #define TSAN_MAYBE_INTERCEPT___FXSTAT TSAN_INTERCEPT(__fxstat) #else #define TSAN_MAYBE_INTERCEPT___FXSTAT #endif TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) { #if SANITIZER_FREEBSD SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf); if (fd > 0) FdAccess(thr, pc, fd); return REAL(fstat)(fd, buf); #else SCOPED_TSAN_INTERCEPTOR(__fxstat, 0, fd, buf); if (fd > 0) FdAccess(thr, pc, fd); return REAL(__fxstat)(0, fd, buf); #endif } #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) { SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf); if (fd > 0) FdAccess(thr, pc, fd); return REAL(__fxstat64)(version, fd, buf); } #define TSAN_MAYBE_INTERCEPT___FXSTAT64 TSAN_INTERCEPT(__fxstat64) #else #define TSAN_MAYBE_INTERCEPT___FXSTAT64 #endif #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) { SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf); if (fd > 0) FdAccess(thr, pc, fd); return REAL(__fxstat64)(0, fd, buf); } #define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64) #else #define TSAN_MAYBE_INTERCEPT_FSTAT64 #endif TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) { SCOPED_TSAN_INTERCEPTOR(open, name, flags, mode); int fd = REAL(open)(name, flags, mode); if (fd >= 0) FdFileCreate(thr, pc, fd); return fd; } #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) { SCOPED_TSAN_INTERCEPTOR(open64, name, flags, mode); int fd = REAL(open64)(name, flags, mode); if (fd >= 0) FdFileCreate(thr, pc, fd); return fd; } #define TSAN_MAYBE_INTERCEPT_OPEN64 TSAN_INTERCEPT(open64) #else #define TSAN_MAYBE_INTERCEPT_OPEN64 #endif TSAN_INTERCEPTOR(int, creat, const char *name, int mode) { SCOPED_TSAN_INTERCEPTOR(creat, name, mode); int fd = REAL(creat)(name, mode); if (fd >= 0) FdFileCreate(thr, pc, fd); return fd; } #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) { SCOPED_TSAN_INTERCEPTOR(creat64, name, mode); int fd = REAL(creat64)(name, mode); if (fd >= 0) FdFileCreate(thr, pc, fd); return fd; } #define TSAN_MAYBE_INTERCEPT_CREAT64 TSAN_INTERCEPT(creat64) #else #define TSAN_MAYBE_INTERCEPT_CREAT64 #endif TSAN_INTERCEPTOR(int, dup, int oldfd) { SCOPED_TSAN_INTERCEPTOR(dup, oldfd); int newfd = REAL(dup)(oldfd); if (oldfd >= 0 && newfd >= 0 && newfd != oldfd) FdDup(thr, pc, oldfd, newfd); return newfd; } TSAN_INTERCEPTOR(int, dup2, int oldfd, int newfd) { SCOPED_TSAN_INTERCEPTOR(dup2, oldfd, newfd); int newfd2 = REAL(dup2)(oldfd, newfd); if (oldfd >= 0 && newfd2 >= 0 && newfd2 != oldfd) FdDup(thr, pc, oldfd, newfd2); return newfd2; } TSAN_INTERCEPTOR(int, dup3, int oldfd, int newfd, int flags) { SCOPED_TSAN_INTERCEPTOR(dup3, oldfd, newfd, flags); int newfd2 = REAL(dup3)(oldfd, newfd, flags); if (oldfd >= 0 && newfd2 >= 0 && newfd2 != oldfd) FdDup(thr, pc, oldfd, newfd2); return newfd2; } #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) { SCOPED_TSAN_INTERCEPTOR(eventfd, initval, flags); int fd = REAL(eventfd)(initval, flags); if (fd >= 0) FdEventCreate(thr, pc, fd); return fd; } #define TSAN_MAYBE_INTERCEPT_EVENTFD TSAN_INTERCEPT(eventfd) #else #define TSAN_MAYBE_INTERCEPT_EVENTFD #endif #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) { SCOPED_TSAN_INTERCEPTOR(signalfd, fd, mask, flags); if (fd >= 0) FdClose(thr, pc, fd); fd = REAL(signalfd)(fd, mask, flags); if (fd >= 0) FdSignalCreate(thr, pc, fd); return fd; } #define TSAN_MAYBE_INTERCEPT_SIGNALFD TSAN_INTERCEPT(signalfd) #else #define TSAN_MAYBE_INTERCEPT_SIGNALFD #endif #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, inotify_init, int fake) { SCOPED_TSAN_INTERCEPTOR(inotify_init, fake); int fd = REAL(inotify_init)(fake); if (fd >= 0) FdInotifyCreate(thr, pc, fd); return fd; } #define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT TSAN_INTERCEPT(inotify_init) #else #define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT #endif #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, inotify_init1, int flags) { SCOPED_TSAN_INTERCEPTOR(inotify_init1, flags); int fd = REAL(inotify_init1)(flags); if (fd >= 0) FdInotifyCreate(thr, pc, fd); return fd; } #define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1 TSAN_INTERCEPT(inotify_init1) #else #define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1 #endif TSAN_INTERCEPTOR(int, socket, int domain, int type, int protocol) { SCOPED_TSAN_INTERCEPTOR(socket, domain, type, protocol); int fd = REAL(socket)(domain, type, protocol); if (fd >= 0) FdSocketCreate(thr, pc, fd); return fd; } TSAN_INTERCEPTOR(int, socketpair, int domain, int type, int protocol, int *fd) { SCOPED_TSAN_INTERCEPTOR(socketpair, domain, type, protocol, fd); int res = REAL(socketpair)(domain, type, protocol, fd); if (res == 0 && fd[0] >= 0 && fd[1] >= 0) FdPipeCreate(thr, pc, fd[0], fd[1]); return res; } TSAN_INTERCEPTOR(int, connect, int fd, void *addr, unsigned addrlen) { SCOPED_TSAN_INTERCEPTOR(connect, fd, addr, addrlen); FdSocketConnecting(thr, pc, fd); int res = REAL(connect)(fd, addr, addrlen); if (res == 0 && fd >= 0) FdSocketConnect(thr, pc, fd); return res; } TSAN_INTERCEPTOR(int, bind, int fd, void *addr, unsigned addrlen) { SCOPED_TSAN_INTERCEPTOR(bind, fd, addr, addrlen); int res = REAL(bind)(fd, addr, addrlen); if (fd > 0 && res == 0) FdAccess(thr, pc, fd); return res; } TSAN_INTERCEPTOR(int, listen, int fd, int backlog) { SCOPED_TSAN_INTERCEPTOR(listen, fd, backlog); int res = REAL(listen)(fd, backlog); if (fd > 0 && res == 0) FdAccess(thr, pc, fd); return res; } #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, epoll_create, int size) { SCOPED_TSAN_INTERCEPTOR(epoll_create, size); int fd = REAL(epoll_create)(size); if (fd >= 0) FdPollCreate(thr, pc, fd); return fd; } #define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE TSAN_INTERCEPT(epoll_create) #else #define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE #endif #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, epoll_create1, int flags) { SCOPED_TSAN_INTERCEPTOR(epoll_create1, flags); int fd = REAL(epoll_create1)(flags); if (fd >= 0) FdPollCreate(thr, pc, fd); return fd; } #define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1 TSAN_INTERCEPT(epoll_create1) #else #define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1 #endif TSAN_INTERCEPTOR(int, close, int fd) { SCOPED_TSAN_INTERCEPTOR(close, fd); if (fd >= 0) FdClose(thr, pc, fd); return REAL(close)(fd); } #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, __close, int fd) { SCOPED_TSAN_INTERCEPTOR(__close, fd); if (fd >= 0) FdClose(thr, pc, fd); return REAL(__close)(fd); } #define TSAN_MAYBE_INTERCEPT___CLOSE TSAN_INTERCEPT(__close) #else #define TSAN_MAYBE_INTERCEPT___CLOSE #endif // glibc guts #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) { SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr); int fds[64]; int cnt = ExtractResolvFDs(state, fds, ARRAY_SIZE(fds)); for (int i = 0; i < cnt; i++) { if (fds[i] > 0) FdClose(thr, pc, fds[i]); } REAL(__res_iclose)(state, free_addr); } #define TSAN_MAYBE_INTERCEPT___RES_ICLOSE TSAN_INTERCEPT(__res_iclose) #else #define TSAN_MAYBE_INTERCEPT___RES_ICLOSE #endif TSAN_INTERCEPTOR(int, pipe, int *pipefd) { SCOPED_TSAN_INTERCEPTOR(pipe, pipefd); int res = REAL(pipe)(pipefd); if (res == 0 && pipefd[0] >= 0 && pipefd[1] >= 0) FdPipeCreate(thr, pc, pipefd[0], pipefd[1]); return res; } TSAN_INTERCEPTOR(int, pipe2, int *pipefd, int flags) { SCOPED_TSAN_INTERCEPTOR(pipe2, pipefd, flags); int res = REAL(pipe2)(pipefd, flags); if (res == 0 && pipefd[0] >= 0 && pipefd[1] >= 0) FdPipeCreate(thr, pc, pipefd[0], pipefd[1]); return res; } TSAN_INTERCEPTOR(long_t, send, int fd, void *buf, long_t len, int flags) { SCOPED_TSAN_INTERCEPTOR(send, fd, buf, len, flags); if (fd >= 0) { FdAccess(thr, pc, fd); FdRelease(thr, pc, fd); } int res = REAL(send)(fd, buf, len, flags); return res; } TSAN_INTERCEPTOR(long_t, sendmsg, int fd, void *msg, int flags) { SCOPED_TSAN_INTERCEPTOR(sendmsg, fd, msg, flags); if (fd >= 0) { FdAccess(thr, pc, fd); FdRelease(thr, pc, fd); } int res = REAL(sendmsg)(fd, msg, flags); return res; } TSAN_INTERCEPTOR(long_t, recv, int fd, void *buf, long_t len, int flags) { SCOPED_TSAN_INTERCEPTOR(recv, fd, buf, len, flags); if (fd >= 0) FdAccess(thr, pc, fd); int res = REAL(recv)(fd, buf, len, flags); if (res >= 0 && fd >= 0) { FdAcquire(thr, pc, fd); } return res; } TSAN_INTERCEPTOR(int, unlink, char *path) { SCOPED_TSAN_INTERCEPTOR(unlink, path); Release(thr, pc, File2addr(path)); int res = REAL(unlink)(path); return res; } TSAN_INTERCEPTOR(void*, tmpfile, int fake) { SCOPED_TSAN_INTERCEPTOR(tmpfile, fake); void *res = REAL(tmpfile)(fake); if (res) { int fd = fileno_unlocked(res); if (fd >= 0) FdFileCreate(thr, pc, fd); } return res; } #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(void*, tmpfile64, int fake) { SCOPED_TSAN_INTERCEPTOR(tmpfile64, fake); void *res = REAL(tmpfile64)(fake); if (res) { int fd = fileno_unlocked(res); if (fd >= 0) FdFileCreate(thr, pc, fd); } return res; } #define TSAN_MAYBE_INTERCEPT_TMPFILE64 TSAN_INTERCEPT(tmpfile64) #else #define TSAN_MAYBE_INTERCEPT_TMPFILE64 #endif TSAN_INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) { // libc file streams can call user-supplied functions, see fopencookie. { SCOPED_TSAN_INTERCEPTOR(fread, ptr, size, nmemb, f); MemoryAccessRange(thr, pc, (uptr)ptr, size * nmemb, true); } return REAL(fread)(ptr, size, nmemb, f); } TSAN_INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) { // libc file streams can call user-supplied functions, see fopencookie. { SCOPED_TSAN_INTERCEPTOR(fwrite, p, size, nmemb, f); MemoryAccessRange(thr, pc, (uptr)p, size * nmemb, false); } return REAL(fwrite)(p, size, nmemb, f); } static void FlushStreams() { // Flushing all the streams here may freeze the process if a child thread is // performing file stream operations at the same time. REAL(fflush)(stdout); REAL(fflush)(stderr); } TSAN_INTERCEPTOR(void, abort, int fake) { SCOPED_TSAN_INTERCEPTOR(abort, fake); FlushStreams(); REAL(abort)(fake); } TSAN_INTERCEPTOR(int, puts, const char *s) { SCOPED_TSAN_INTERCEPTOR(puts, s); MemoryAccessRange(thr, pc, (uptr)s, internal_strlen(s), false); return REAL(puts)(s); } TSAN_INTERCEPTOR(int, rmdir, char *path) { SCOPED_TSAN_INTERCEPTOR(rmdir, path); Release(thr, pc, Dir2addr(path)); int res = REAL(rmdir)(path); return res; } TSAN_INTERCEPTOR(int, closedir, void *dirp) { SCOPED_TSAN_INTERCEPTOR(closedir, dirp); int fd = dirfd(dirp); FdClose(thr, pc, fd); return REAL(closedir)(dirp); } #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) { SCOPED_TSAN_INTERCEPTOR(epoll_ctl, epfd, op, fd, ev); if (epfd >= 0) FdAccess(thr, pc, epfd); if (epfd >= 0 && fd >= 0) FdAccess(thr, pc, fd); if (op == EPOLL_CTL_ADD && epfd >= 0) FdRelease(thr, pc, epfd); int res = REAL(epoll_ctl)(epfd, op, fd, ev); return res; } #define TSAN_MAYBE_INTERCEPT_EPOLL_CTL TSAN_INTERCEPT(epoll_ctl) #else #define TSAN_MAYBE_INTERCEPT_EPOLL_CTL #endif #if !SANITIZER_FREEBSD TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) { SCOPED_TSAN_INTERCEPTOR(epoll_wait, epfd, ev, cnt, timeout); if (epfd >= 0) FdAccess(thr, pc, epfd); int res = BLOCK_REAL(epoll_wait)(epfd, ev, cnt, timeout); if (res > 0 && epfd >= 0) FdAcquire(thr, pc, epfd); return res; } #define TSAN_MAYBE_INTERCEPT_EPOLL_WAIT TSAN_INTERCEPT(epoll_wait) #else #define TSAN_MAYBE_INTERCEPT_EPOLL_WAIT #endif namespace __tsan { static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire, bool sigact, int sig, my_siginfo_t *info, void *uctx) { if (acquire) Acquire(thr, 0, (uptr)&sigactions[sig]); // Ensure that the handler does not spoil errno. const int saved_errno = errno; errno = 99; // This code races with sigaction. Be careful to not read sa_sigaction twice. // Also need to remember pc for reporting before the call, // because the handler can reset it. volatile uptr pc = sigact ? (uptr)sigactions[sig].sa_sigaction : (uptr)sigactions[sig].sa_handler; if (pc != (uptr)SIG_DFL && pc != (uptr)SIG_IGN) { if (sigact) ((sigactionhandler_t)pc)(sig, info, uctx); else ((sighandler_t)pc)(sig); } // We do not detect errno spoiling for SIGTERM, // because some SIGTERM handlers do spoil errno but reraise SIGTERM, // tsan reports false positive in such case. // It's difficult to properly detect this situation (reraise), // because in async signal processing case (when handler is called directly // from rtl_generic_sighandler) we have not yet received the reraised // signal; and it looks too fragile to intercept all ways to reraise a signal. if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) { VarSizeStackTrace stack; - // Add 1 to pc because return address is expected, - // OutputReport() will undo this. - ObtainCurrentStack(thr, pc + 1, &stack); + // StackTrace::GetNestInstructionPc(pc) is used because return address is + // expected, OutputReport() will undo this. + ObtainCurrentStack(thr, StackTrace::GetNextInstructionPc(pc), &stack); ThreadRegistryLock l(ctx->thread_registry); ScopedReport rep(ReportTypeErrnoInSignal); if (!IsFiredSuppression(ctx, rep, stack)) { rep.AddStack(stack, true); OutputReport(thr, rep); } } errno = saved_errno; } void ProcessPendingSignals(ThreadState *thr) { SignalContext *sctx = SigCtx(thr); if (sctx == 0 || atomic_load(&sctx->have_pending_signals, memory_order_relaxed) == 0) return; atomic_store(&sctx->have_pending_signals, 0, memory_order_relaxed); atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed); // These are too big for stack. static THREADLOCAL __sanitizer_sigset_t emptyset, oldset; REAL(sigfillset)(&emptyset); pthread_sigmask(SIG_SETMASK, &emptyset, &oldset); for (int sig = 0; sig < kSigCount; sig++) { SignalDesc *signal = &sctx->pending_signals[sig]; if (signal->armed) { signal->armed = false; CallUserSignalHandler(thr, false, true, signal->sigaction, sig, &signal->siginfo, &signal->ctx); } } pthread_sigmask(SIG_SETMASK, &oldset, 0); atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed); } } // namespace __tsan static bool is_sync_signal(SignalContext *sctx, int sig) { return sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS || // If we are sending signal to ourselves, we must process it now. (sctx && sig == sctx->int_signal_send); } void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig, my_siginfo_t *info, void *ctx) { ThreadState *thr = cur_thread(); SignalContext *sctx = SigCtx(thr); if (sig < 0 || sig >= kSigCount) { VPrintf(1, "ThreadSanitizer: ignoring signal %d\n", sig); return; } // Don't mess with synchronous signals. const bool sync = is_sync_signal(sctx, sig); if (sync || // If we are in blocking function, we can safely process it now // (but check if we are in a recursive interceptor, // i.e. pthread_join()->munmap()). (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed))) { atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed); if (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed)) { // We ignore interceptors in blocking functions, // temporary enbled them again while we are calling user function. int const i = thr->ignore_interceptors; thr->ignore_interceptors = 0; atomic_store(&sctx->in_blocking_func, 0, memory_order_relaxed); CallUserSignalHandler(thr, sync, true, sigact, sig, info, ctx); thr->ignore_interceptors = i; atomic_store(&sctx->in_blocking_func, 1, memory_order_relaxed); } else { // Be very conservative with when we do acquire in this case. // It's unsafe to do acquire in async handlers, because ThreadState // can be in inconsistent state. // SIGSYS looks relatively safe -- it's synchronous and can actually // need some global state. bool acq = (sig == SIGSYS); CallUserSignalHandler(thr, sync, acq, sigact, sig, info, ctx); } atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed); return; } if (sctx == 0) return; SignalDesc *signal = &sctx->pending_signals[sig]; if (signal->armed == false) { signal->armed = true; signal->sigaction = sigact; if (info) internal_memcpy(&signal->siginfo, info, sizeof(*info)); if (ctx) internal_memcpy(&signal->ctx, ctx, sizeof(signal->ctx)); atomic_store(&sctx->have_pending_signals, 1, memory_order_relaxed); } } static void rtl_sighandler(int sig) { rtl_generic_sighandler(false, sig, 0, 0); } static void rtl_sigaction(int sig, my_siginfo_t *info, void *ctx) { rtl_generic_sighandler(true, sig, info, ctx); } TSAN_INTERCEPTOR(int, sigaction, int sig, sigaction_t *act, sigaction_t *old) { SCOPED_TSAN_INTERCEPTOR(sigaction, sig, act, old); if (old) internal_memcpy(old, &sigactions[sig], sizeof(*old)); if (act == 0) return 0; // Copy act into sigactions[sig]. // Can't use struct copy, because compiler can emit call to memcpy. // Can't use internal_memcpy, because it copies byte-by-byte, // and signal handler reads the sa_handler concurrently. It it can read // some bytes from old value and some bytes from new value. // Use volatile to prevent insertion of memcpy. sigactions[sig].sa_handler = *(volatile sighandler_t*)&act->sa_handler; sigactions[sig].sa_flags = *(volatile int*)&act->sa_flags; internal_memcpy(&sigactions[sig].sa_mask, &act->sa_mask, sizeof(sigactions[sig].sa_mask)); #if !SANITIZER_FREEBSD sigactions[sig].sa_restorer = act->sa_restorer; #endif sigaction_t newact; internal_memcpy(&newact, act, sizeof(newact)); REAL(sigfillset)(&newact.sa_mask); if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL) { if (newact.sa_flags & SA_SIGINFO) newact.sa_sigaction = rtl_sigaction; else newact.sa_handler = rtl_sighandler; } ReleaseStore(thr, pc, (uptr)&sigactions[sig]); int res = REAL(sigaction)(sig, &newact, 0); return res; } TSAN_INTERCEPTOR(sighandler_t, signal, int sig, sighandler_t h) { sigaction_t act; act.sa_handler = h; REAL(memset)(&act.sa_mask, -1, sizeof(act.sa_mask)); act.sa_flags = 0; sigaction_t old; int res = sigaction(sig, &act, &old); if (res) return SIG_ERR; return old.sa_handler; } TSAN_INTERCEPTOR(int, sigsuspend, const __sanitizer_sigset_t *mask) { SCOPED_TSAN_INTERCEPTOR(sigsuspend, mask); return REAL(sigsuspend)(mask); } TSAN_INTERCEPTOR(int, raise, int sig) { SCOPED_TSAN_INTERCEPTOR(raise, sig); SignalContext *sctx = SigCtx(thr); CHECK_NE(sctx, 0); int prev = sctx->int_signal_send; sctx->int_signal_send = sig; int res = REAL(raise)(sig); CHECK_EQ(sctx->int_signal_send, sig); sctx->int_signal_send = prev; return res; } TSAN_INTERCEPTOR(int, kill, int pid, int sig) { SCOPED_TSAN_INTERCEPTOR(kill, pid, sig); SignalContext *sctx = SigCtx(thr); CHECK_NE(sctx, 0); int prev = sctx->int_signal_send; if (pid == (int)internal_getpid()) { sctx->int_signal_send = sig; } int res = REAL(kill)(pid, sig); if (pid == (int)internal_getpid()) { CHECK_EQ(sctx->int_signal_send, sig); sctx->int_signal_send = prev; } return res; } TSAN_INTERCEPTOR(int, pthread_kill, void *tid, int sig) { SCOPED_TSAN_INTERCEPTOR(pthread_kill, tid, sig); SignalContext *sctx = SigCtx(thr); CHECK_NE(sctx, 0); int prev = sctx->int_signal_send; if (tid == pthread_self()) { sctx->int_signal_send = sig; } int res = REAL(pthread_kill)(tid, sig); if (tid == pthread_self()) { CHECK_EQ(sctx->int_signal_send, sig); sctx->int_signal_send = prev; } return res; } TSAN_INTERCEPTOR(int, gettimeofday, void *tv, void *tz) { SCOPED_TSAN_INTERCEPTOR(gettimeofday, tv, tz); // It's intercepted merely to process pending signals. return REAL(gettimeofday)(tv, tz); } TSAN_INTERCEPTOR(int, getaddrinfo, void *node, void *service, void *hints, void *rv) { SCOPED_TSAN_INTERCEPTOR(getaddrinfo, node, service, hints, rv); // We miss atomic synchronization in getaddrinfo, // and can report false race between malloc and free // inside of getaddrinfo. So ignore memory accesses. ThreadIgnoreBegin(thr, pc); int res = REAL(getaddrinfo)(node, service, hints, rv); ThreadIgnoreEnd(thr, pc); return res; } TSAN_INTERCEPTOR(int, fork, int fake) { if (cur_thread()->in_symbolizer) return REAL(fork)(fake); SCOPED_INTERCEPTOR_RAW(fork, fake); ForkBefore(thr, pc); int pid = REAL(fork)(fake); if (pid == 0) { // child ForkChildAfter(thr, pc); FdOnFork(thr, pc); } else if (pid > 0) { // parent ForkParentAfter(thr, pc); } else { // error ForkParentAfter(thr, pc); } return pid; } TSAN_INTERCEPTOR(int, vfork, int fake) { // Some programs (e.g. openjdk) call close for all file descriptors // in the child process. Under tsan it leads to false positives, because // address space is shared, so the parent process also thinks that // the descriptors are closed (while they are actually not). // This leads to false positives due to missed synchronization. // Strictly saying this is undefined behavior, because vfork child is not // allowed to call any functions other than exec/exit. But this is what // openjdk does, so we want to handle it. // We could disable interceptors in the child process. But it's not possible // to simply intercept and wrap vfork, because vfork child is not allowed // to return from the function that calls vfork, and that's exactly what // we would do. So this would require some assembly trickery as well. // Instead we simply turn vfork into fork. return WRAP(fork)(fake); } static int OnExit(ThreadState *thr) { int status = Finalize(thr); FlushStreams(); return status; } struct TsanInterceptorContext { ThreadState *thr; const uptr caller_pc; const uptr pc; }; static void HandleRecvmsg(ThreadState *thr, uptr pc, __sanitizer_msghdr *msg) { int fds[64]; int cnt = ExtractRecvmsgFDs(msg, fds, ARRAY_SIZE(fds)); for (int i = 0; i < cnt; i++) FdEventCreate(thr, pc, fds[i]); } #include "sanitizer_common/sanitizer_platform_interceptors.h" // Causes interceptor recursion (getaddrinfo() and fopen()) #undef SANITIZER_INTERCEPT_GETADDRINFO // There interceptors do not seem to be strictly necessary for tsan. // But we see cases where the interceptors consume 70% of execution time. // Memory blocks passed to fgetgrent_r are "written to" by tsan several times. // First, there is some recursion (getgrnam_r calls fgetgrent_r), and each // function "writes to" the buffer. Then, the same memory is "written to" // twice, first as buf and then as pwbufp (both of them refer to the same // addresses). #undef SANITIZER_INTERCEPT_GETPWENT #undef SANITIZER_INTERCEPT_GETPWENT_R #undef SANITIZER_INTERCEPT_FGETPWENT #undef SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS #undef SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS // __tls_get_addr can be called with mis-aligned stack due to: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066 // There are two potential issues: // 1. Sanitizer code contains a MOVDQA spill (it does not seem to be the case // right now). or 2. ProcessPendingSignal calls user handler which contains // MOVDQA spill (this happens right now). // Since the interceptor only initializes memory for msan, the simplest solution // is to disable the interceptor in tsan (other sanitizers do not call // signal handlers from COMMON_INTERCEPTOR_ENTER). #undef SANITIZER_INTERCEPT_TLS_GET_ADDR #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ MemoryAccessRange(((TsanInterceptorContext *)ctx)->thr, \ ((TsanInterceptorContext *)ctx)->pc, (uptr)ptr, size, \ true) #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ MemoryAccessRange(((TsanInterceptorContext *) ctx)->thr, \ ((TsanInterceptorContext *) ctx)->pc, (uptr) ptr, size, \ false) #define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ SCOPED_TSAN_INTERCEPTOR(func, __VA_ARGS__); \ TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \ ctx = (void *)&_ctx; \ (void) ctx; #define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, func, ...) \ SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \ TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \ ctx = (void *)&_ctx; \ (void) ctx; #define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) \ Acquire(thr, pc, File2addr(path)); \ if (file) { \ int fd = fileno_unlocked(file); \ if (fd >= 0) FdFileCreate(thr, pc, fd); \ } #define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) \ if (file) { \ int fd = fileno_unlocked(file); \ if (fd >= 0) FdClose(thr, pc, fd); \ } #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ libignore()->OnLibraryLoaded(filename) #define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() \ libignore()->OnLibraryUnloaded() #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ Acquire(((TsanInterceptorContext *) ctx)->thr, pc, Dir2addr(path)) #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ FdAcquire(((TsanInterceptorContext *) ctx)->thr, pc, fd) #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ FdRelease(((TsanInterceptorContext *) ctx)->thr, pc, fd) #define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) \ FdAccess(((TsanInterceptorContext *) ctx)->thr, pc, fd) #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ FdSocketAccept(((TsanInterceptorContext *) ctx)->thr, pc, fd, newfd) #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \ ThreadSetName(((TsanInterceptorContext *) ctx)->thr, name) #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ __tsan::ctx->thread_registry->SetThreadNameByUserId(thread, name) #define COMMON_INTERCEPTOR_BLOCK_REAL(name) BLOCK_REAL(name) #define COMMON_INTERCEPTOR_ON_EXIT(ctx) \ OnExit(((TsanInterceptorContext *) ctx)->thr) #define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) \ MutexLock(((TsanInterceptorContext *)ctx)->thr, \ ((TsanInterceptorContext *)ctx)->pc, (uptr)m) #define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \ MutexUnlock(((TsanInterceptorContext *)ctx)->thr, \ ((TsanInterceptorContext *)ctx)->pc, (uptr)m) #define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) \ MutexRepair(((TsanInterceptorContext *)ctx)->thr, \ ((TsanInterceptorContext *)ctx)->pc, (uptr)m) #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \ HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \ ((TsanInterceptorContext *)ctx)->pc, msg) #include "sanitizer_common/sanitizer_common_interceptors.inc" #define TSAN_SYSCALL() \ ThreadState *thr = cur_thread(); \ if (thr->ignore_interceptors) \ return; \ ScopedSyscall scoped_syscall(thr) \ /**/ struct ScopedSyscall { ThreadState *thr; explicit ScopedSyscall(ThreadState *thr) : thr(thr) { Initialize(thr); } ~ScopedSyscall() { ProcessPendingSignals(thr); } }; static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) { TSAN_SYSCALL(); MemoryAccessRange(thr, pc, p, s, write); } static void syscall_acquire(uptr pc, uptr addr) { TSAN_SYSCALL(); Acquire(thr, pc, addr); DPrintf("syscall_acquire(%p)\n", addr); } static void syscall_release(uptr pc, uptr addr) { TSAN_SYSCALL(); DPrintf("syscall_release(%p)\n", addr); Release(thr, pc, addr); } static void syscall_fd_close(uptr pc, int fd) { TSAN_SYSCALL(); FdClose(thr, pc, fd); } static USED void syscall_fd_acquire(uptr pc, int fd) { TSAN_SYSCALL(); FdAcquire(thr, pc, fd); DPrintf("syscall_fd_acquire(%p)\n", fd); } static USED void syscall_fd_release(uptr pc, int fd) { TSAN_SYSCALL(); DPrintf("syscall_fd_release(%p)\n", fd); FdRelease(thr, pc, fd); } static void syscall_pre_fork(uptr pc) { TSAN_SYSCALL(); ForkBefore(thr, pc); } static void syscall_post_fork(uptr pc, int pid) { TSAN_SYSCALL(); if (pid == 0) { // child ForkChildAfter(thr, pc); FdOnFork(thr, pc); } else if (pid > 0) { // parent ForkParentAfter(thr, pc); } else { // error ForkParentAfter(thr, pc); } } #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) \ syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), false) #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \ syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), true) #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) #define COMMON_SYSCALL_ACQUIRE(addr) \ syscall_acquire(GET_CALLER_PC(), (uptr)(addr)) #define COMMON_SYSCALL_RELEASE(addr) \ syscall_release(GET_CALLER_PC(), (uptr)(addr)) #define COMMON_SYSCALL_FD_CLOSE(fd) syscall_fd_close(GET_CALLER_PC(), fd) #define COMMON_SYSCALL_FD_ACQUIRE(fd) syscall_fd_acquire(GET_CALLER_PC(), fd) #define COMMON_SYSCALL_FD_RELEASE(fd) syscall_fd_release(GET_CALLER_PC(), fd) #define COMMON_SYSCALL_PRE_FORK() \ syscall_pre_fork(GET_CALLER_PC()) #define COMMON_SYSCALL_POST_FORK(res) \ syscall_post_fork(GET_CALLER_PC(), res) #include "sanitizer_common/sanitizer_common_syscalls.inc" namespace __tsan { static void finalize(void *arg) { ThreadState *thr = cur_thread(); int status = Finalize(thr); // Make sure the output is not lost. FlushStreams(); if (status) REAL(_exit)(status); } static void unreachable() { Report("FATAL: ThreadSanitizer: unreachable called\n"); Die(); } void InitializeInterceptors() { // We need to setup it early, because functions like dlsym() can call it. REAL(memset) = internal_memset; REAL(memcpy) = internal_memcpy; REAL(memcmp) = internal_memcmp; // Instruct libc malloc to consume less memory. #if !SANITIZER_FREEBSD mallopt(1, 0); // M_MXFAST mallopt(-3, 32*1024); // M_MMAP_THRESHOLD #endif InitializeCommonInterceptors(); // We can not use TSAN_INTERCEPT to get setjmp addr, // because it does &setjmp and setjmp is not present in some versions of libc. using __interception::GetRealFunctionAddress; GetRealFunctionAddress("setjmp", (uptr*)&REAL(setjmp), 0, 0); GetRealFunctionAddress("_setjmp", (uptr*)&REAL(_setjmp), 0, 0); GetRealFunctionAddress("sigsetjmp", (uptr*)&REAL(sigsetjmp), 0, 0); GetRealFunctionAddress("__sigsetjmp", (uptr*)&REAL(__sigsetjmp), 0, 0); TSAN_INTERCEPT(longjmp); TSAN_INTERCEPT(siglongjmp); TSAN_INTERCEPT(malloc); TSAN_INTERCEPT(__libc_memalign); TSAN_INTERCEPT(calloc); TSAN_INTERCEPT(realloc); TSAN_INTERCEPT(free); TSAN_INTERCEPT(cfree); TSAN_INTERCEPT(mmap); TSAN_MAYBE_INTERCEPT_MMAP64; TSAN_INTERCEPT(munmap); TSAN_MAYBE_INTERCEPT_MEMALIGN; TSAN_INTERCEPT(valloc); TSAN_MAYBE_INTERCEPT_PVALLOC; TSAN_INTERCEPT(posix_memalign); TSAN_INTERCEPT(strlen); TSAN_INTERCEPT(memset); TSAN_INTERCEPT(memcpy); TSAN_INTERCEPT(memmove); TSAN_INTERCEPT(memcmp); TSAN_INTERCEPT(strchr); TSAN_INTERCEPT(strchrnul); TSAN_INTERCEPT(strrchr); TSAN_INTERCEPT(strcpy); // NOLINT TSAN_INTERCEPT(strncpy); TSAN_INTERCEPT(strstr); TSAN_INTERCEPT(strdup); TSAN_INTERCEPT(pthread_create); TSAN_INTERCEPT(pthread_join); TSAN_INTERCEPT(pthread_detach); TSAN_INTERCEPT_VER(pthread_cond_init, "GLIBC_2.3.2"); TSAN_INTERCEPT_VER(pthread_cond_signal, "GLIBC_2.3.2"); TSAN_INTERCEPT_VER(pthread_cond_broadcast, "GLIBC_2.3.2"); TSAN_INTERCEPT_VER(pthread_cond_wait, "GLIBC_2.3.2"); TSAN_INTERCEPT_VER(pthread_cond_timedwait, "GLIBC_2.3.2"); TSAN_INTERCEPT_VER(pthread_cond_destroy, "GLIBC_2.3.2"); TSAN_INTERCEPT(pthread_mutex_init); TSAN_INTERCEPT(pthread_mutex_destroy); TSAN_INTERCEPT(pthread_mutex_trylock); TSAN_INTERCEPT(pthread_mutex_timedlock); TSAN_INTERCEPT(pthread_spin_init); TSAN_INTERCEPT(pthread_spin_destroy); TSAN_INTERCEPT(pthread_spin_lock); TSAN_INTERCEPT(pthread_spin_trylock); TSAN_INTERCEPT(pthread_spin_unlock); TSAN_INTERCEPT(pthread_rwlock_init); TSAN_INTERCEPT(pthread_rwlock_destroy); TSAN_INTERCEPT(pthread_rwlock_rdlock); TSAN_INTERCEPT(pthread_rwlock_tryrdlock); TSAN_INTERCEPT(pthread_rwlock_timedrdlock); TSAN_INTERCEPT(pthread_rwlock_wrlock); TSAN_INTERCEPT(pthread_rwlock_trywrlock); TSAN_INTERCEPT(pthread_rwlock_timedwrlock); TSAN_INTERCEPT(pthread_rwlock_unlock); TSAN_INTERCEPT(pthread_barrier_init); TSAN_INTERCEPT(pthread_barrier_destroy); TSAN_INTERCEPT(pthread_barrier_wait); TSAN_INTERCEPT(pthread_once); TSAN_INTERCEPT(sem_init); TSAN_INTERCEPT(sem_destroy); TSAN_INTERCEPT(sem_wait); TSAN_INTERCEPT(sem_trywait); TSAN_INTERCEPT(sem_timedwait); TSAN_INTERCEPT(sem_post); TSAN_INTERCEPT(sem_getvalue); TSAN_INTERCEPT(stat); TSAN_MAYBE_INTERCEPT___XSTAT; TSAN_MAYBE_INTERCEPT_STAT64; TSAN_MAYBE_INTERCEPT___XSTAT64; TSAN_INTERCEPT(lstat); TSAN_MAYBE_INTERCEPT___LXSTAT; TSAN_MAYBE_INTERCEPT_LSTAT64; TSAN_MAYBE_INTERCEPT___LXSTAT64; TSAN_INTERCEPT(fstat); TSAN_MAYBE_INTERCEPT___FXSTAT; TSAN_MAYBE_INTERCEPT_FSTAT64; TSAN_MAYBE_INTERCEPT___FXSTAT64; TSAN_INTERCEPT(open); TSAN_MAYBE_INTERCEPT_OPEN64; TSAN_INTERCEPT(creat); TSAN_MAYBE_INTERCEPT_CREAT64; TSAN_INTERCEPT(dup); TSAN_INTERCEPT(dup2); TSAN_INTERCEPT(dup3); TSAN_MAYBE_INTERCEPT_EVENTFD; TSAN_MAYBE_INTERCEPT_SIGNALFD; TSAN_MAYBE_INTERCEPT_INOTIFY_INIT; TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1; TSAN_INTERCEPT(socket); TSAN_INTERCEPT(socketpair); TSAN_INTERCEPT(connect); TSAN_INTERCEPT(bind); TSAN_INTERCEPT(listen); TSAN_MAYBE_INTERCEPT_EPOLL_CREATE; TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1; TSAN_INTERCEPT(close); TSAN_MAYBE_INTERCEPT___CLOSE; TSAN_MAYBE_INTERCEPT___RES_ICLOSE; TSAN_INTERCEPT(pipe); TSAN_INTERCEPT(pipe2); TSAN_INTERCEPT(send); TSAN_INTERCEPT(sendmsg); TSAN_INTERCEPT(recv); TSAN_INTERCEPT(unlink); TSAN_INTERCEPT(tmpfile); TSAN_MAYBE_INTERCEPT_TMPFILE64; TSAN_INTERCEPT(fread); TSAN_INTERCEPT(fwrite); TSAN_INTERCEPT(abort); TSAN_INTERCEPT(puts); TSAN_INTERCEPT(rmdir); TSAN_INTERCEPT(closedir); TSAN_MAYBE_INTERCEPT_EPOLL_CTL; TSAN_MAYBE_INTERCEPT_EPOLL_WAIT; TSAN_INTERCEPT(sigaction); TSAN_INTERCEPT(signal); TSAN_INTERCEPT(sigsuspend); TSAN_INTERCEPT(raise); TSAN_INTERCEPT(kill); TSAN_INTERCEPT(pthread_kill); TSAN_INTERCEPT(sleep); TSAN_INTERCEPT(usleep); TSAN_INTERCEPT(nanosleep); TSAN_INTERCEPT(gettimeofday); TSAN_INTERCEPT(getaddrinfo); TSAN_INTERCEPT(fork); TSAN_INTERCEPT(vfork); TSAN_INTERCEPT(on_exit); TSAN_INTERCEPT(__cxa_atexit); TSAN_INTERCEPT(_exit); // Need to setup it, because interceptors check that the function is resolved. // But atexit is emitted directly into the module, so can't be resolved. REAL(atexit) = (int(*)(void(*)()))unreachable; if (REAL(__cxa_atexit)(&finalize, 0, 0)) { Printf("ThreadSanitizer: failed to setup atexit callback\n"); Die(); } if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { Printf("ThreadSanitizer: failed to create thread key\n"); Die(); } FdInit(); } } // namespace __tsan Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cc (revision 279194) @@ -1,953 +1,954 @@ //===-- tsan_interface_atomic.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 ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// // ThreadSanitizer atomic operations are based on C++11/C1x standards. // For background see C++11 standard. A slightly older, publicly // available draft of the standard (not entirely up-to-date, but close enough // for casual browsing) is available here: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf // The following page contains more background information: // http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/ #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_mutex.h" #include "tsan_flags.h" #include "tsan_rtl.h" using namespace __tsan; // NOLINT // These should match declarations from public tsan_interface_atomic.h header. typedef unsigned char a8; typedef unsigned short a16; // NOLINT typedef unsigned int a32; typedef unsigned long long a64; // NOLINT #if !defined(SANITIZER_GO) && (defined(__SIZEOF_INT128__) \ - || (__clang_major__ * 100 + __clang_minor__ >= 302)) + || (__clang_major__ * 100 + __clang_minor__ >= 302)) && !defined(__mips64) __extension__ typedef __int128 a128; # define __TSAN_HAS_INT128 1 #else # define __TSAN_HAS_INT128 0 #endif -#ifndef SANITIZER_GO +#if !defined(SANITIZER_GO) && __TSAN_HAS_INT128 // Protects emulation of 128-bit atomic operations. static StaticSpinMutex mutex128; #endif // Part of ABI, do not change. // http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/atomic?view=markup typedef enum { mo_relaxed, mo_consume, mo_acquire, mo_release, mo_acq_rel, mo_seq_cst } morder; static bool IsLoadOrder(morder mo) { return mo == mo_relaxed || mo == mo_consume || mo == mo_acquire || mo == mo_seq_cst; } static bool IsStoreOrder(morder mo) { return mo == mo_relaxed || mo == mo_release || mo == mo_seq_cst; } static bool IsReleaseOrder(morder mo) { return mo == mo_release || mo == mo_acq_rel || mo == mo_seq_cst; } static bool IsAcquireOrder(morder mo) { return mo == mo_consume || mo == mo_acquire || mo == mo_acq_rel || mo == mo_seq_cst; } static bool IsAcqRelOrder(morder mo) { return mo == mo_acq_rel || mo == mo_seq_cst; } template T func_xchg(volatile T *v, T op) { T res = __sync_lock_test_and_set(v, op); // __sync_lock_test_and_set does not contain full barrier. __sync_synchronize(); return res; } template T func_add(volatile T *v, T op) { return __sync_fetch_and_add(v, op); } template T func_sub(volatile T *v, T op) { return __sync_fetch_and_sub(v, op); } template T func_and(volatile T *v, T op) { return __sync_fetch_and_and(v, op); } template T func_or(volatile T *v, T op) { return __sync_fetch_and_or(v, op); } template T func_xor(volatile T *v, T op) { return __sync_fetch_and_xor(v, op); } template T func_nand(volatile T *v, T op) { // clang does not support __sync_fetch_and_nand. T cmp = *v; for (;;) { T newv = ~(cmp & op); T cur = __sync_val_compare_and_swap(v, cmp, newv); if (cmp == cur) return cmp; cmp = cur; } } template T func_cas(volatile T *v, T cmp, T xch) { return __sync_val_compare_and_swap(v, cmp, xch); } // clang does not support 128-bit atomic ops. // Atomic ops are executed under tsan internal mutex, // here we assume that the atomic variables are not accessed // from non-instrumented code. -#if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) && !defined(SANITIZER_GO) +#if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) && !defined(SANITIZER_GO) \ + && __TSAN_HAS_INT128 a128 func_xchg(volatile a128 *v, a128 op) { SpinMutexLock lock(&mutex128); a128 cmp = *v; *v = op; return cmp; } a128 func_add(volatile a128 *v, a128 op) { SpinMutexLock lock(&mutex128); a128 cmp = *v; *v = cmp + op; return cmp; } a128 func_sub(volatile a128 *v, a128 op) { SpinMutexLock lock(&mutex128); a128 cmp = *v; *v = cmp - op; return cmp; } a128 func_and(volatile a128 *v, a128 op) { SpinMutexLock lock(&mutex128); a128 cmp = *v; *v = cmp & op; return cmp; } a128 func_or(volatile a128 *v, a128 op) { SpinMutexLock lock(&mutex128); a128 cmp = *v; *v = cmp | op; return cmp; } a128 func_xor(volatile a128 *v, a128 op) { SpinMutexLock lock(&mutex128); a128 cmp = *v; *v = cmp ^ op; return cmp; } a128 func_nand(volatile a128 *v, a128 op) { SpinMutexLock lock(&mutex128); a128 cmp = *v; *v = ~(cmp & op); return cmp; } a128 func_cas(volatile a128 *v, a128 cmp, a128 xch) { SpinMutexLock lock(&mutex128); a128 cur = *v; if (cur == cmp) *v = xch; return cur; } #endif template static int SizeLog() { if (sizeof(T) <= 1) return kSizeLog1; else if (sizeof(T) <= 2) return kSizeLog2; else if (sizeof(T) <= 4) return kSizeLog4; else return kSizeLog8; // For 16-byte atomics we also use 8-byte memory access, // this leads to false negatives only in very obscure cases. } #ifndef SANITIZER_GO static atomic_uint8_t *to_atomic(const volatile a8 *a) { return reinterpret_cast(const_cast(a)); } static atomic_uint16_t *to_atomic(const volatile a16 *a) { return reinterpret_cast(const_cast(a)); } #endif static atomic_uint32_t *to_atomic(const volatile a32 *a) { return reinterpret_cast(const_cast(a)); } static atomic_uint64_t *to_atomic(const volatile a64 *a) { return reinterpret_cast(const_cast(a)); } static memory_order to_mo(morder mo) { switch (mo) { case mo_relaxed: return memory_order_relaxed; case mo_consume: return memory_order_consume; case mo_acquire: return memory_order_acquire; case mo_release: return memory_order_release; case mo_acq_rel: return memory_order_acq_rel; case mo_seq_cst: return memory_order_seq_cst; } CHECK(0); return memory_order_seq_cst; } template static T NoTsanAtomicLoad(const volatile T *a, morder mo) { return atomic_load(to_atomic(a), to_mo(mo)); } #if __TSAN_HAS_INT128 && !defined(SANITIZER_GO) static a128 NoTsanAtomicLoad(const volatile a128 *a, morder mo) { SpinMutexLock lock(&mutex128); return *a; } #endif template static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a, morder mo) { CHECK(IsLoadOrder(mo)); // This fast-path is critical for performance. // Assume the access is atomic. if (!IsAcquireOrder(mo)) { MemoryReadAtomic(thr, pc, (uptr)a, SizeLog()); return NoTsanAtomicLoad(a, mo); } SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, false); AcquireImpl(thr, pc, &s->clock); T v = NoTsanAtomicLoad(a, mo); s->mtx.ReadUnlock(); MemoryReadAtomic(thr, pc, (uptr)a, SizeLog()); return v; } template static void NoTsanAtomicStore(volatile T *a, T v, morder mo) { atomic_store(to_atomic(a), v, to_mo(mo)); } #if __TSAN_HAS_INT128 && !defined(SANITIZER_GO) static void NoTsanAtomicStore(volatile a128 *a, a128 v, morder mo) { SpinMutexLock lock(&mutex128); *a = v; } #endif template static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) { CHECK(IsStoreOrder(mo)); MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog()); // This fast-path is critical for performance. // Assume the access is atomic. // Strictly saying even relaxed store cuts off release sequence, // so must reset the clock. if (!IsReleaseOrder(mo)) { NoTsanAtomicStore(a, v, mo); return; } __sync_synchronize(); SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, true); thr->fast_state.IncrementEpoch(); // Can't increment epoch w/o writing to the trace as well. TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); ReleaseImpl(thr, pc, &s->clock); NoTsanAtomicStore(a, v, mo); s->mtx.Unlock(); } template static T AtomicRMW(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) { MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog()); SyncVar *s = 0; if (mo != mo_relaxed) { s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, true); thr->fast_state.IncrementEpoch(); // Can't increment epoch w/o writing to the trace as well. TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); if (IsAcqRelOrder(mo)) AcquireReleaseImpl(thr, pc, &s->clock); else if (IsReleaseOrder(mo)) ReleaseImpl(thr, pc, &s->clock); else if (IsAcquireOrder(mo)) AcquireImpl(thr, pc, &s->clock); } v = F(a, v); if (s) s->mtx.Unlock(); return v; } template static T NoTsanAtomicExchange(volatile T *a, T v, morder mo) { return func_xchg(a, v); } template static T NoTsanAtomicFetchAdd(volatile T *a, T v, morder mo) { return func_add(a, v); } template static T NoTsanAtomicFetchSub(volatile T *a, T v, morder mo) { return func_sub(a, v); } template static T NoTsanAtomicFetchAnd(volatile T *a, T v, morder mo) { return func_and(a, v); } template static T NoTsanAtomicFetchOr(volatile T *a, T v, morder mo) { return func_or(a, v); } template static T NoTsanAtomicFetchXor(volatile T *a, T v, morder mo) { return func_xor(a, v); } template static T NoTsanAtomicFetchNand(volatile T *a, T v, morder mo) { return func_nand(a, v); } template static T AtomicExchange(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) { return AtomicRMW(thr, pc, a, v, mo); } template static T AtomicFetchAdd(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) { return AtomicRMW(thr, pc, a, v, mo); } template static T AtomicFetchSub(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) { return AtomicRMW(thr, pc, a, v, mo); } template static T AtomicFetchAnd(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) { return AtomicRMW(thr, pc, a, v, mo); } template static T AtomicFetchOr(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) { return AtomicRMW(thr, pc, a, v, mo); } template static T AtomicFetchXor(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) { return AtomicRMW(thr, pc, a, v, mo); } template static T AtomicFetchNand(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) { return AtomicRMW(thr, pc, a, v, mo); } template static bool NoTsanAtomicCAS(volatile T *a, T *c, T v, morder mo, morder fmo) { return atomic_compare_exchange_strong(to_atomic(a), c, v, to_mo(mo)); } #if __TSAN_HAS_INT128 static bool NoTsanAtomicCAS(volatile a128 *a, a128 *c, a128 v, morder mo, morder fmo) { a128 old = *c; a128 cur = func_cas(a, old, v); if (cur == old) return true; *c = cur; return false; } #endif template static T NoTsanAtomicCAS(volatile T *a, T c, T v, morder mo, morder fmo) { NoTsanAtomicCAS(a, &c, v, mo, fmo); return c; } template static bool AtomicCAS(ThreadState *thr, uptr pc, volatile T *a, T *c, T v, morder mo, morder fmo) { (void)fmo; // Unused because llvm does not pass it yet. MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog()); SyncVar *s = 0; bool write_lock = mo != mo_acquire && mo != mo_consume; if (mo != mo_relaxed) { s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, write_lock); thr->fast_state.IncrementEpoch(); // Can't increment epoch w/o writing to the trace as well. TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); if (IsAcqRelOrder(mo)) AcquireReleaseImpl(thr, pc, &s->clock); else if (IsReleaseOrder(mo)) ReleaseImpl(thr, pc, &s->clock); else if (IsAcquireOrder(mo)) AcquireImpl(thr, pc, &s->clock); } T cc = *c; T pr = func_cas(a, cc, v); if (s) { if (write_lock) s->mtx.Unlock(); else s->mtx.ReadUnlock(); } if (pr == cc) return true; *c = pr; return false; } template static T AtomicCAS(ThreadState *thr, uptr pc, volatile T *a, T c, T v, morder mo, morder fmo) { AtomicCAS(thr, pc, a, &c, v, mo, fmo); return c; } #ifndef SANITIZER_GO static void NoTsanAtomicFence(morder mo) { __sync_synchronize(); } static void AtomicFence(ThreadState *thr, uptr pc, morder mo) { // FIXME(dvyukov): not implemented. __sync_synchronize(); } #endif // Interface functions follow. #ifndef SANITIZER_GO // C/C++ #define SCOPED_ATOMIC(func, ...) \ const uptr callpc = (uptr)__builtin_return_address(0); \ uptr pc = StackTrace::GetCurrentPc(); \ mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \ ThreadState *const thr = cur_thread(); \ if (thr->ignore_interceptors) \ return NoTsanAtomic##func(__VA_ARGS__); \ AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \ ScopedAtomic sa(thr, callpc, a, mo, __func__); \ return Atomic##func(thr, pc, __VA_ARGS__); \ /**/ class ScopedAtomic { public: ScopedAtomic(ThreadState *thr, uptr pc, const volatile void *a, morder mo, const char *func) : thr_(thr) { FuncEntry(thr_, pc); DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo); } ~ScopedAtomic() { ProcessPendingSignals(thr_); FuncExit(thr_); } private: ThreadState *thr_; }; static void AtomicStatInc(ThreadState *thr, uptr size, morder mo, StatType t) { StatInc(thr, StatAtomic); StatInc(thr, t); StatInc(thr, size == 1 ? StatAtomic1 : size == 2 ? StatAtomic2 : size == 4 ? StatAtomic4 : size == 8 ? StatAtomic8 : StatAtomic16); StatInc(thr, mo == mo_relaxed ? StatAtomicRelaxed : mo == mo_consume ? StatAtomicConsume : mo == mo_acquire ? StatAtomicAcquire : mo == mo_release ? StatAtomicRelease : mo == mo_acq_rel ? StatAtomicAcq_Rel : StatAtomicSeq_Cst); } extern "C" { SANITIZER_INTERFACE_ATTRIBUTE a8 __tsan_atomic8_load(const volatile a8 *a, morder mo) { SCOPED_ATOMIC(Load, a, mo); } SANITIZER_INTERFACE_ATTRIBUTE a16 __tsan_atomic16_load(const volatile a16 *a, morder mo) { SCOPED_ATOMIC(Load, a, mo); } SANITIZER_INTERFACE_ATTRIBUTE a32 __tsan_atomic32_load(const volatile a32 *a, morder mo) { SCOPED_ATOMIC(Load, a, mo); } SANITIZER_INTERFACE_ATTRIBUTE a64 __tsan_atomic64_load(const volatile a64 *a, morder mo) { SCOPED_ATOMIC(Load, a, mo); } #if __TSAN_HAS_INT128 SANITIZER_INTERFACE_ATTRIBUTE a128 __tsan_atomic128_load(const volatile a128 *a, morder mo) { SCOPED_ATOMIC(Load, a, mo); } #endif SANITIZER_INTERFACE_ATTRIBUTE void __tsan_atomic8_store(volatile a8 *a, a8 v, morder mo) { SCOPED_ATOMIC(Store, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE void __tsan_atomic16_store(volatile a16 *a, a16 v, morder mo) { SCOPED_ATOMIC(Store, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE void __tsan_atomic32_store(volatile a32 *a, a32 v, morder mo) { SCOPED_ATOMIC(Store, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE void __tsan_atomic64_store(volatile a64 *a, a64 v, morder mo) { SCOPED_ATOMIC(Store, a, v, mo); } #if __TSAN_HAS_INT128 SANITIZER_INTERFACE_ATTRIBUTE void __tsan_atomic128_store(volatile a128 *a, a128 v, morder mo) { SCOPED_ATOMIC(Store, a, v, mo); } #endif SANITIZER_INTERFACE_ATTRIBUTE a8 __tsan_atomic8_exchange(volatile a8 *a, a8 v, morder mo) { SCOPED_ATOMIC(Exchange, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a16 __tsan_atomic16_exchange(volatile a16 *a, a16 v, morder mo) { SCOPED_ATOMIC(Exchange, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a32 __tsan_atomic32_exchange(volatile a32 *a, a32 v, morder mo) { SCOPED_ATOMIC(Exchange, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a64 __tsan_atomic64_exchange(volatile a64 *a, a64 v, morder mo) { SCOPED_ATOMIC(Exchange, a, v, mo); } #if __TSAN_HAS_INT128 SANITIZER_INTERFACE_ATTRIBUTE a128 __tsan_atomic128_exchange(volatile a128 *a, a128 v, morder mo) { SCOPED_ATOMIC(Exchange, a, v, mo); } #endif SANITIZER_INTERFACE_ATTRIBUTE a8 __tsan_atomic8_fetch_add(volatile a8 *a, a8 v, morder mo) { SCOPED_ATOMIC(FetchAdd, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a16 __tsan_atomic16_fetch_add(volatile a16 *a, a16 v, morder mo) { SCOPED_ATOMIC(FetchAdd, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a32 __tsan_atomic32_fetch_add(volatile a32 *a, a32 v, morder mo) { SCOPED_ATOMIC(FetchAdd, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a64 __tsan_atomic64_fetch_add(volatile a64 *a, a64 v, morder mo) { SCOPED_ATOMIC(FetchAdd, a, v, mo); } #if __TSAN_HAS_INT128 SANITIZER_INTERFACE_ATTRIBUTE a128 __tsan_atomic128_fetch_add(volatile a128 *a, a128 v, morder mo) { SCOPED_ATOMIC(FetchAdd, a, v, mo); } #endif SANITIZER_INTERFACE_ATTRIBUTE a8 __tsan_atomic8_fetch_sub(volatile a8 *a, a8 v, morder mo) { SCOPED_ATOMIC(FetchSub, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a16 __tsan_atomic16_fetch_sub(volatile a16 *a, a16 v, morder mo) { SCOPED_ATOMIC(FetchSub, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a32 __tsan_atomic32_fetch_sub(volatile a32 *a, a32 v, morder mo) { SCOPED_ATOMIC(FetchSub, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a64 __tsan_atomic64_fetch_sub(volatile a64 *a, a64 v, morder mo) { SCOPED_ATOMIC(FetchSub, a, v, mo); } #if __TSAN_HAS_INT128 SANITIZER_INTERFACE_ATTRIBUTE a128 __tsan_atomic128_fetch_sub(volatile a128 *a, a128 v, morder mo) { SCOPED_ATOMIC(FetchSub, a, v, mo); } #endif SANITIZER_INTERFACE_ATTRIBUTE a8 __tsan_atomic8_fetch_and(volatile a8 *a, a8 v, morder mo) { SCOPED_ATOMIC(FetchAnd, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a16 __tsan_atomic16_fetch_and(volatile a16 *a, a16 v, morder mo) { SCOPED_ATOMIC(FetchAnd, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a32 __tsan_atomic32_fetch_and(volatile a32 *a, a32 v, morder mo) { SCOPED_ATOMIC(FetchAnd, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a64 __tsan_atomic64_fetch_and(volatile a64 *a, a64 v, morder mo) { SCOPED_ATOMIC(FetchAnd, a, v, mo); } #if __TSAN_HAS_INT128 SANITIZER_INTERFACE_ATTRIBUTE a128 __tsan_atomic128_fetch_and(volatile a128 *a, a128 v, morder mo) { SCOPED_ATOMIC(FetchAnd, a, v, mo); } #endif SANITIZER_INTERFACE_ATTRIBUTE a8 __tsan_atomic8_fetch_or(volatile a8 *a, a8 v, morder mo) { SCOPED_ATOMIC(FetchOr, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a16 __tsan_atomic16_fetch_or(volatile a16 *a, a16 v, morder mo) { SCOPED_ATOMIC(FetchOr, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a32 __tsan_atomic32_fetch_or(volatile a32 *a, a32 v, morder mo) { SCOPED_ATOMIC(FetchOr, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a64 __tsan_atomic64_fetch_or(volatile a64 *a, a64 v, morder mo) { SCOPED_ATOMIC(FetchOr, a, v, mo); } #if __TSAN_HAS_INT128 SANITIZER_INTERFACE_ATTRIBUTE a128 __tsan_atomic128_fetch_or(volatile a128 *a, a128 v, morder mo) { SCOPED_ATOMIC(FetchOr, a, v, mo); } #endif SANITIZER_INTERFACE_ATTRIBUTE a8 __tsan_atomic8_fetch_xor(volatile a8 *a, a8 v, morder mo) { SCOPED_ATOMIC(FetchXor, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a16 __tsan_atomic16_fetch_xor(volatile a16 *a, a16 v, morder mo) { SCOPED_ATOMIC(FetchXor, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a32 __tsan_atomic32_fetch_xor(volatile a32 *a, a32 v, morder mo) { SCOPED_ATOMIC(FetchXor, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a64 __tsan_atomic64_fetch_xor(volatile a64 *a, a64 v, morder mo) { SCOPED_ATOMIC(FetchXor, a, v, mo); } #if __TSAN_HAS_INT128 SANITIZER_INTERFACE_ATTRIBUTE a128 __tsan_atomic128_fetch_xor(volatile a128 *a, a128 v, morder mo) { SCOPED_ATOMIC(FetchXor, a, v, mo); } #endif SANITIZER_INTERFACE_ATTRIBUTE a8 __tsan_atomic8_fetch_nand(volatile a8 *a, a8 v, morder mo) { SCOPED_ATOMIC(FetchNand, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a16 __tsan_atomic16_fetch_nand(volatile a16 *a, a16 v, morder mo) { SCOPED_ATOMIC(FetchNand, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a32 __tsan_atomic32_fetch_nand(volatile a32 *a, a32 v, morder mo) { SCOPED_ATOMIC(FetchNand, a, v, mo); } SANITIZER_INTERFACE_ATTRIBUTE a64 __tsan_atomic64_fetch_nand(volatile a64 *a, a64 v, morder mo) { SCOPED_ATOMIC(FetchNand, a, v, mo); } #if __TSAN_HAS_INT128 SANITIZER_INTERFACE_ATTRIBUTE a128 __tsan_atomic128_fetch_nand(volatile a128 *a, a128 v, morder mo) { SCOPED_ATOMIC(FetchNand, a, v, mo); } #endif SANITIZER_INTERFACE_ATTRIBUTE int __tsan_atomic8_compare_exchange_strong(volatile a8 *a, a8 *c, a8 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } SANITIZER_INTERFACE_ATTRIBUTE int __tsan_atomic16_compare_exchange_strong(volatile a16 *a, a16 *c, a16 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } SANITIZER_INTERFACE_ATTRIBUTE int __tsan_atomic32_compare_exchange_strong(volatile a32 *a, a32 *c, a32 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } SANITIZER_INTERFACE_ATTRIBUTE int __tsan_atomic64_compare_exchange_strong(volatile a64 *a, a64 *c, a64 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } #if __TSAN_HAS_INT128 SANITIZER_INTERFACE_ATTRIBUTE int __tsan_atomic128_compare_exchange_strong(volatile a128 *a, a128 *c, a128 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } #endif SANITIZER_INTERFACE_ATTRIBUTE int __tsan_atomic8_compare_exchange_weak(volatile a8 *a, a8 *c, a8 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } SANITIZER_INTERFACE_ATTRIBUTE int __tsan_atomic16_compare_exchange_weak(volatile a16 *a, a16 *c, a16 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } SANITIZER_INTERFACE_ATTRIBUTE int __tsan_atomic32_compare_exchange_weak(volatile a32 *a, a32 *c, a32 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } SANITIZER_INTERFACE_ATTRIBUTE int __tsan_atomic64_compare_exchange_weak(volatile a64 *a, a64 *c, a64 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } #if __TSAN_HAS_INT128 SANITIZER_INTERFACE_ATTRIBUTE int __tsan_atomic128_compare_exchange_weak(volatile a128 *a, a128 *c, a128 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } #endif SANITIZER_INTERFACE_ATTRIBUTE a8 __tsan_atomic8_compare_exchange_val(volatile a8 *a, a8 c, a8 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } SANITIZER_INTERFACE_ATTRIBUTE a16 __tsan_atomic16_compare_exchange_val(volatile a16 *a, a16 c, a16 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } SANITIZER_INTERFACE_ATTRIBUTE a32 __tsan_atomic32_compare_exchange_val(volatile a32 *a, a32 c, a32 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } SANITIZER_INTERFACE_ATTRIBUTE a64 __tsan_atomic64_compare_exchange_val(volatile a64 *a, a64 c, a64 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } #if __TSAN_HAS_INT128 SANITIZER_INTERFACE_ATTRIBUTE a128 __tsan_atomic128_compare_exchange_val(volatile a128 *a, a128 c, a128 v, morder mo, morder fmo) { SCOPED_ATOMIC(CAS, a, c, v, mo, fmo); } #endif SANITIZER_INTERFACE_ATTRIBUTE void __tsan_atomic_thread_fence(morder mo) { char* a = 0; SCOPED_ATOMIC(Fence, mo); } SANITIZER_INTERFACE_ATTRIBUTE void __tsan_atomic_signal_fence(morder mo) { } } // extern "C" #else // #ifndef SANITIZER_GO // Go #define ATOMIC(func, ...) \ if (thr->ignore_sync) { \ NoTsanAtomic##func(__VA_ARGS__); \ } else { \ FuncEntry(thr, cpc); \ Atomic##func(thr, pc, __VA_ARGS__); \ FuncExit(thr); \ } \ /**/ #define ATOMIC_RET(func, ret, ...) \ if (thr->ignore_sync) { \ (ret) = NoTsanAtomic##func(__VA_ARGS__); \ } else { \ FuncEntry(thr, cpc); \ (ret) = Atomic##func(thr, pc, __VA_ARGS__); \ FuncExit(thr); \ } \ /**/ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __tsan_go_atomic32_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { ATOMIC_RET(Load, *(a32*)(a+8), *(a32**)a, mo_acquire); } SANITIZER_INTERFACE_ATTRIBUTE void __tsan_go_atomic64_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { ATOMIC_RET(Load, *(a64*)(a+8), *(a64**)a, mo_acquire); } SANITIZER_INTERFACE_ATTRIBUTE void __tsan_go_atomic32_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { ATOMIC(Store, *(a32**)a, *(a32*)(a+8), mo_release); } SANITIZER_INTERFACE_ATTRIBUTE void __tsan_go_atomic64_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { ATOMIC(Store, *(a64**)a, *(a64*)(a+8), mo_release); } SANITIZER_INTERFACE_ATTRIBUTE void __tsan_go_atomic32_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { ATOMIC_RET(FetchAdd, *(a32*)(a+16), *(a32**)a, *(a32*)(a+8), mo_acq_rel); } SANITIZER_INTERFACE_ATTRIBUTE void __tsan_go_atomic64_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { ATOMIC_RET(FetchAdd, *(a64*)(a+16), *(a64**)a, *(a64*)(a+8), mo_acq_rel); } SANITIZER_INTERFACE_ATTRIBUTE void __tsan_go_atomic32_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { ATOMIC_RET(Exchange, *(a32*)(a+16), *(a32**)a, *(a32*)(a+8), mo_acq_rel); } SANITIZER_INTERFACE_ATTRIBUTE void __tsan_go_atomic64_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a) { ATOMIC_RET(Exchange, *(a64*)(a+16), *(a64**)a, *(a64*)(a+8), mo_acq_rel); } SANITIZER_INTERFACE_ATTRIBUTE void __tsan_go_atomic32_compare_exchange( ThreadState *thr, uptr cpc, uptr pc, u8 *a) { a32 cur = 0; a32 cmp = *(a32*)(a+8); ATOMIC_RET(CAS, cur, *(a32**)a, cmp, *(a32*)(a+12), mo_acq_rel, mo_acquire); *(bool*)(a+16) = (cur == cmp); } SANITIZER_INTERFACE_ATTRIBUTE void __tsan_go_atomic64_compare_exchange( ThreadState *thr, uptr cpc, uptr pc, u8 *a) { a64 cur = 0; a64 cmp = *(a64*)(a+8); ATOMIC_RET(CAS, cur, *(a64**)a, cmp, *(a64*)(a+16), mo_acq_rel, mo_acquire); *(bool*)(a+24) = (cur == cmp); } } // extern "C" #endif // #ifndef SANITIZER_GO Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_platform.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_platform.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_platform.h (revision 279194) @@ -1,267 +1,299 @@ //===-- tsan_platform.h -----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of ThreadSanitizer (TSan), a race detector. // // Platform-specific code. //===----------------------------------------------------------------------===// #ifndef TSAN_PLATFORM_H #define TSAN_PLATFORM_H #if !defined(__LP64__) && !defined(_WIN64) # error "Only 64-bit is supported" #endif #include "tsan_defs.h" #include "tsan_trace.h" namespace __tsan { #if !defined(SANITIZER_GO) +#if defined(__x86_64__) /* -C/C++ on linux and freebsd +C/C++ on linux/x86_64 and freebsd/x86_64 0000 0000 1000 - 0100 0000 0000: main binary and/or MAP_32BIT mappings 0100 0000 0000 - 0200 0000 0000: - 0200 0000 0000 - 1000 0000 0000: shadow 1000 0000 0000 - 3000 0000 0000: - 3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects) 4000 0000 0000 - 6000 0000 0000: - 6000 0000 0000 - 6200 0000 0000: traces 6200 0000 0000 - 7d00 0000 0000: - 7d00 0000 0000 - 7e00 0000 0000: heap 7e00 0000 0000 - 7e80 0000 0000: - 7e80 0000 0000 - 8000 0000 0000: modules and main thread stack */ - const uptr kMetaShadowBeg = 0x300000000000ull; const uptr kMetaShadowEnd = 0x400000000000ull; const uptr kTraceMemBeg = 0x600000000000ull; const uptr kTraceMemEnd = 0x620000000000ull; const uptr kShadowBeg = 0x020000000000ull; const uptr kShadowEnd = 0x100000000000ull; const uptr kHeapMemBeg = 0x7d0000000000ull; const uptr kHeapMemEnd = 0x7e0000000000ull; const uptr kLoAppMemBeg = 0x000000001000ull; const uptr kLoAppMemEnd = 0x010000000000ull; const uptr kHiAppMemBeg = 0x7e8000000000ull; const uptr kHiAppMemEnd = 0x800000000000ull; const uptr kAppMemMsk = 0x7c0000000000ull; const uptr kAppMemXor = 0x020000000000ull; +const uptr kVdsoBeg = 0xf000000000000000ull; +#elif defined(__mips64) +/* +C/C++ on linux/mips64 +0100 0000 00 - 0200 0000 00: main binary +0200 0000 00 - 1400 0000 00: - +1400 0000 00 - 2400 0000 00: shadow +2400 0000 00 - 3000 0000 00: - +3000 0000 00 - 4000 0000 00: metainfo (memory blocks and sync objects) +4000 0000 00 - 6000 0000 00: - +6000 0000 00 - 6200 0000 00: traces +6200 0000 00 - fe00 0000 00: - +fe00 0000 00 - ff00 0000 00: heap +ff00 0000 00 - ff80 0000 00: - +ff80 0000 00 - ffff ffff ff: modules and main thread stack +*/ +const uptr kMetaShadowBeg = 0x3000000000ull; +const uptr kMetaShadowEnd = 0x4000000000ull; +const uptr kTraceMemBeg = 0x6000000000ull; +const uptr kTraceMemEnd = 0x6200000000ull; +const uptr kShadowBeg = 0x1400000000ull; +const uptr kShadowEnd = 0x2400000000ull; +const uptr kHeapMemBeg = 0xfe00000000ull; +const uptr kHeapMemEnd = 0xff00000000ull; +const uptr kLoAppMemBeg = 0x0100000000ull; +const uptr kLoAppMemEnd = 0x0200000000ull; +const uptr kHiAppMemBeg = 0xff80000000ull; +const uptr kHiAppMemEnd = 0xffffffffffull; +const uptr kAppMemMsk = 0xfc00000000ull; +const uptr kAppMemXor = 0x0400000000ull; +const uptr kVdsoBeg = 0xfffff00000ull; +#endif ALWAYS_INLINE bool IsAppMem(uptr mem) { return (mem >= kHeapMemBeg && mem < kHeapMemEnd) || (mem >= kLoAppMemBeg && mem < kLoAppMemEnd) || (mem >= kHiAppMemBeg && mem < kHiAppMemEnd); } ALWAYS_INLINE bool IsShadowMem(uptr mem) { return mem >= kShadowBeg && mem <= kShadowEnd; } ALWAYS_INLINE bool IsMetaMem(uptr mem) { return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd; } ALWAYS_INLINE uptr MemToShadow(uptr x) { DCHECK(IsAppMem(x)); return (((x) & ~(kAppMemMsk | (kShadowCell - 1))) ^ kAppMemXor) * kShadowCnt; } ALWAYS_INLINE u32 *MemToMeta(uptr x) { DCHECK(IsAppMem(x)); return (u32*)(((((x) & ~(kAppMemMsk | (kMetaShadowCell - 1))) ^ kAppMemXor) / kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg); } ALWAYS_INLINE uptr ShadowToMem(uptr s) { CHECK(IsShadowMem(s)); if (s >= MemToShadow(kLoAppMemBeg) && s <= MemToShadow(kLoAppMemEnd - 1)) return (s / kShadowCnt) ^ kAppMemXor; else return ((s / kShadowCnt) ^ kAppMemXor) | kAppMemMsk; } static USED uptr UserRegions[] = { kLoAppMemBeg, kLoAppMemEnd, kHiAppMemBeg, kHiAppMemEnd, kHeapMemBeg, kHeapMemEnd, }; #elif defined(SANITIZER_GO) && !SANITIZER_WINDOWS /* Go on linux, darwin and freebsd 0000 0000 1000 - 0000 1000 0000: executable 0000 1000 0000 - 00c0 0000 0000: - 00c0 0000 0000 - 00e0 0000 0000: heap 00e0 0000 0000 - 2000 0000 0000: - 2000 0000 0000 - 2380 0000 0000: shadow 2380 0000 0000 - 3000 0000 0000: - 3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects) 4000 0000 0000 - 6000 0000 0000: - 6000 0000 0000 - 6200 0000 0000: traces 6200 0000 0000 - 8000 0000 0000: - */ const uptr kMetaShadowBeg = 0x300000000000ull; const uptr kMetaShadowEnd = 0x400000000000ull; const uptr kTraceMemBeg = 0x600000000000ull; const uptr kTraceMemEnd = 0x620000000000ull; const uptr kShadowBeg = 0x200000000000ull; const uptr kShadowEnd = 0x238000000000ull; const uptr kAppMemBeg = 0x000000001000ull; const uptr kAppMemEnd = 0x00e000000000ull; ALWAYS_INLINE bool IsAppMem(uptr mem) { return mem >= kAppMemBeg && mem < kAppMemEnd; } ALWAYS_INLINE bool IsShadowMem(uptr mem) { return mem >= kShadowBeg && mem <= kShadowEnd; } ALWAYS_INLINE bool IsMetaMem(uptr mem) { return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd; } ALWAYS_INLINE uptr MemToShadow(uptr x) { DCHECK(IsAppMem(x)); return ((x & ~(kShadowCell - 1)) * kShadowCnt) | kShadowBeg; } ALWAYS_INLINE u32 *MemToMeta(uptr x) { DCHECK(IsAppMem(x)); return (u32*)(((x & ~(kMetaShadowCell - 1)) / \ kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg); } ALWAYS_INLINE uptr ShadowToMem(uptr s) { CHECK(IsShadowMem(s)); return (s & ~kShadowBeg) / kShadowCnt; } static USED uptr UserRegions[] = { kAppMemBeg, kAppMemEnd, }; #elif defined(SANITIZER_GO) && SANITIZER_WINDOWS /* Go on windows 0000 0000 1000 - 0000 1000 0000: executable 0000 1000 0000 - 00f8 0000 0000: - 00c0 0000 0000 - 00e0 0000 0000: heap 00e0 0000 0000 - 0100 0000 0000: - -0100 0000 0000 - 0380 0000 0000: shadow -0380 0000 0000 - 0560 0000 0000: - +0100 0000 0000 - 0500 0000 0000: shadow +0500 0000 0000 - 0560 0000 0000: - 0560 0000 0000 - 0760 0000 0000: traces 0760 0000 0000 - 07d0 0000 0000: metainfo (memory blocks and sync objects) 07d0 0000 0000 - 8000 0000 0000: - */ const uptr kMetaShadowBeg = 0x076000000000ull; const uptr kMetaShadowEnd = 0x07d000000000ull; const uptr kTraceMemBeg = 0x056000000000ull; const uptr kTraceMemEnd = 0x076000000000ull; const uptr kShadowBeg = 0x010000000000ull; -const uptr kShadowEnd = 0x038000000000ull; +const uptr kShadowEnd = 0x050000000000ull; const uptr kAppMemBeg = 0x000000001000ull; const uptr kAppMemEnd = 0x00e000000000ull; ALWAYS_INLINE bool IsAppMem(uptr mem) { return mem >= kAppMemBeg && mem < kAppMemEnd; } ALWAYS_INLINE bool IsShadowMem(uptr mem) { return mem >= kShadowBeg && mem <= kShadowEnd; } ALWAYS_INLINE bool IsMetaMem(uptr mem) { return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd; } ALWAYS_INLINE uptr MemToShadow(uptr x) { DCHECK(IsAppMem(x)); - return ((x & ~(kShadowCell - 1)) * kShadowCnt) | kShadowBeg; + return ((x & ~(kShadowCell - 1)) * kShadowCnt) + kShadowBeg; } ALWAYS_INLINE u32 *MemToMeta(uptr x) { DCHECK(IsAppMem(x)); return (u32*)(((x & ~(kMetaShadowCell - 1)) / \ - kMetaShadowCell * kMetaShadowSize) | kMetaShadowEnd); + kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg); } ALWAYS_INLINE uptr ShadowToMem(uptr s) { CHECK(IsShadowMem(s)); // FIXME(dvyukov): this is most likely wrong as the mapping is not bijection. - return (x & ~kShadowBeg) / kShadowCnt; + return (s - kShadowBeg) / kShadowCnt; } static USED uptr UserRegions[] = { kAppMemBeg, kAppMemEnd, }; #else # error "Unknown platform" #endif // The additional page is to catch shadow stack overflow as paging fault. // Windows wants 64K alignment for mmaps. const uptr kTotalTraceSize = (kTraceSize * sizeof(Event) + sizeof(Trace) + (64 << 10) + (64 << 10) - 1) & ~((64 << 10) - 1); uptr ALWAYS_INLINE GetThreadTrace(int tid) { uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize; DCHECK_LT(p, kTraceMemEnd); return p; } uptr ALWAYS_INLINE GetThreadTraceHeader(int tid) { uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize + kTraceSize * sizeof(Event); DCHECK_LT(p, kTraceMemEnd); return p; } void InitializePlatform(); void FlushShadowMemory(); void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive); // Says whether the addr relates to a global var. // Guesses with high probability, may yield both false positives and negatives. bool IsGlobalVar(uptr addr); int ExtractResolvFDs(void *state, int *fds, int nfd); int ExtractRecvmsgFDs(void *msg, int *fds, int nfd); int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m, void *abstime), void *c, void *m, void *abstime, void(*cleanup)(void *arg), void *arg); } // namespace __tsan #endif // TSAN_PLATFORM_H Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc (revision 279194) @@ -1,407 +1,412 @@ //===-- tsan_platform_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 ThreadSanitizer (TSan), a race detector. // // Linux- and FreeBSD-specific code. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_LINUX || SANITIZER_FREEBSD #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_procmaps.h" #include "sanitizer_common/sanitizer_stoptheworld.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "tsan_platform.h" #include "tsan_rtl.h" #include "tsan_flags.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if SANITIZER_LINUX #define __need_res_state #include #endif #ifdef sa_handler # undef sa_handler #endif #ifdef sa_sigaction # undef sa_sigaction #endif #if SANITIZER_FREEBSD extern "C" void *__libc_stack_end; void *__libc_stack_end = 0; #endif namespace __tsan { static uptr g_data_start; static uptr g_data_end; -const uptr kPageSize = 4096; - enum { MemTotal = 0, MemShadow = 1, MemMeta = 2, MemFile = 3, MemMmap = 4, MemTrace = 5, MemHeap = 6, MemOther = 7, MemCount = 8, }; void FillProfileCallback(uptr p, uptr rss, bool file, uptr *mem, uptr stats_size) { mem[MemTotal] += rss; if (p >= kShadowBeg && p < kShadowEnd) mem[MemShadow] += rss; else if (p >= kMetaShadowBeg && p < kMetaShadowEnd) mem[MemMeta] += rss; #ifndef SANITIZER_GO else if (p >= kHeapMemBeg && p < kHeapMemEnd) mem[MemHeap] += rss; else if (p >= kLoAppMemBeg && p < kLoAppMemEnd) mem[file ? MemFile : MemMmap] += rss; else if (p >= kHiAppMemBeg && p < kHiAppMemEnd) mem[file ? MemFile : MemMmap] += rss; #else else if (p >= kAppMemBeg && p < kAppMemEnd) mem[file ? MemFile : MemMmap] += rss; #endif else if (p >= kTraceMemBeg && p < kTraceMemEnd) mem[MemTrace] += rss; else mem[MemOther] += rss; } void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) { uptr mem[MemCount] = {}; __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7); StackDepotStats *stacks = StackDepotGetStats(); internal_snprintf(buf, buf_size, "RSS %zd MB: shadow:%zd meta:%zd file:%zd mmap:%zd" " trace:%zd heap:%zd other:%zd stacks=%zd[%zd] nthr=%zd/%zd\n", mem[MemTotal] >> 20, mem[MemShadow] >> 20, mem[MemMeta] >> 20, mem[MemFile] >> 20, mem[MemMmap] >> 20, mem[MemTrace] >> 20, mem[MemHeap] >> 20, mem[MemOther] >> 20, stacks->allocated >> 20, stacks->n_uniq_ids, nlive, nthread); } #if SANITIZER_LINUX void FlushShadowMemoryCallback( const SuspendedThreadsList &suspended_threads_list, void *argument) { FlushUnneededShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg); } #endif void FlushShadowMemory() { #if SANITIZER_LINUX StopTheWorld(FlushShadowMemoryCallback, 0); #endif } #ifndef SANITIZER_GO static void ProtectRange(uptr beg, uptr end) { CHECK_LE(beg, end); if (beg == end) return; if (beg != (uptr)Mprotect(beg, end - beg)) { Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end); Printf("FATAL: Make sure you are not using unlimited stack\n"); Die(); } } // Mark shadow for .rodata sections with the special kShadowRodata marker. // Accesses to .rodata can't race, so this saves time, memory and trace space. static void MapRodata() { // First create temp file. const char *tmpdir = GetEnv("TMPDIR"); if (tmpdir == 0) tmpdir = GetEnv("TEST_TMPDIR"); #ifdef P_tmpdir if (tmpdir == 0) tmpdir = P_tmpdir; #endif if (tmpdir == 0) return; char name[256]; internal_snprintf(name, sizeof(name), "%s/tsan.rodata.%d", tmpdir, (int)internal_getpid()); uptr openrv = internal_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); if (internal_iserror(openrv)) return; internal_unlink(name); // Unlink it now, so that we can reuse the buffer. fd_t fd = openrv; // Fill the file with kShadowRodata. const uptr kMarkerSize = 512 * 1024 / sizeof(u64); InternalScopedBuffer marker(kMarkerSize); // volatile to prevent insertion of memset for (volatile u64 *p = marker.data(); p < marker.data() + kMarkerSize; p++) *p = kShadowRodata; internal_write(fd, marker.data(), marker.size()); // Map the file into memory. - uptr page = internal_mmap(0, kPageSize, PROT_READ | PROT_WRITE, + uptr page = internal_mmap(0, GetPageSizeCached(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, fd, 0); if (internal_iserror(page)) { internal_close(fd); return; } // Map the file into shadow of .rodata sections. MemoryMappingLayout proc_maps(/*cache_enabled*/true); uptr start, end, offset, prot; // Reusing the buffer 'name'. while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), &prot)) { if (name[0] != 0 && name[0] != '[' && (prot & MemoryMappingLayout::kProtectionRead) && (prot & MemoryMappingLayout::kProtectionExecute) && !(prot & MemoryMappingLayout::kProtectionWrite) && IsAppMem(start)) { // Assume it's .rodata char *shadow_start = (char*)MemToShadow(start); char *shadow_end = (char*)MemToShadow(end); for (char *p = shadow_start; p < shadow_end; p += marker.size()) { internal_mmap(p, Min(marker.size(), shadow_end - p), PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0); } } } internal_close(fd); } void InitializeShadowMemory() { // Map memory shadow. uptr shadow = (uptr)MmapFixedNoReserve(kShadowBeg, kShadowEnd - kShadowBeg); if (shadow != kShadowBeg) { Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n"); Printf("FATAL: Make sure to compile with -fPIE and " "to link with -pie (%p, %p).\n", shadow, kShadowBeg); Die(); } // This memory range is used for thread stacks and large user mmaps. // Frequently a thread uses only a small part of stack and similarly // a program uses a small part of large mmap. On some programs // we see 20% memory usage reduction without huge pages for this range. // FIXME: don't use constants here. - NoHugePagesInRegion(MemToShadow(0x7f0000000000ULL), - 0x10000000000ULL * kShadowMultiplier); +#if defined(__x86_64__) + const uptr kMadviseRangeBeg = 0x7f0000000000ull; + const uptr kMadviseRangeSize = 0x010000000000ull; +#elif defined(__mips64) + const uptr kMadviseRangeBeg = 0xff00000000ull; + const uptr kMadviseRangeSize = 0x0100000000ull; +#endif + NoHugePagesInRegion(MemToShadow(kMadviseRangeBeg), + kMadviseRangeSize * kShadowMultiplier); if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg); DPrintf("memory shadow: %zx-%zx (%zuGB)\n", kShadowBeg, kShadowEnd, (kShadowEnd - kShadowBeg) >> 30); // Map meta shadow. uptr meta_size = kMetaShadowEnd - kMetaShadowBeg; uptr meta = (uptr)MmapFixedNoReserve(kMetaShadowBeg, meta_size); if (meta != kMetaShadowBeg) { Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n"); Printf("FATAL: Make sure to compile with -fPIE and " "to link with -pie (%p, %p).\n", meta, kMetaShadowBeg); Die(); } if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(meta, meta_size); DPrintf("meta shadow: %zx-%zx (%zuGB)\n", meta, meta + meta_size, meta_size >> 30); MapRodata(); } static void InitDataSeg() { MemoryMappingLayout proc_maps(true); uptr start, end, offset; char name[128]; #if SANITIZER_FREEBSD // On FreeBSD BSS is usually the last block allocated within the // low range and heap is the last block allocated within the range // 0x800000000-0x8ffffffff. while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), /*protection*/ 0)) { DPrintf("%p-%p %p %s\n", start, end, offset, name); if ((start & 0xffff00000000ULL) == 0 && (end & 0xffff00000000ULL) == 0 && name[0] == '\0') { g_data_start = start; g_data_end = end; } } #else bool prev_is_data = false; while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), /*protection*/ 0)) { DPrintf("%p-%p %p %s\n", start, end, offset, name); bool is_data = offset != 0 && name[0] != 0; // BSS may get merged with [heap] in /proc/self/maps. This is not very // reliable. bool is_bss = offset == 0 && (name[0] == 0 || internal_strcmp(name, "[heap]") == 0) && prev_is_data; if (g_data_start == 0 && is_data) g_data_start = start; if (is_bss) g_data_end = end; prev_is_data = is_data; } #endif DPrintf("guessed data_start=%p data_end=%p\n", g_data_start, g_data_end); CHECK_LT(g_data_start, g_data_end); CHECK_GE((uptr)&g_data_start, g_data_start); CHECK_LT((uptr)&g_data_start, g_data_end); } static void CheckAndProtect() { // Ensure that the binary is indeed compiled with -pie. MemoryMappingLayout proc_maps(true); uptr p, end; while (proc_maps.Next(&p, &end, 0, 0, 0, 0)) { if (IsAppMem(p)) continue; if (p >= kHeapMemEnd && - p < kHeapMemEnd + PrimaryAllocator::AdditionalSize()) + p < HeapEnd()) continue; - if (p >= 0xf000000000000000ull) // vdso + if (p >= kVdsoBeg) // vdso break; Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", p, end); Die(); } ProtectRange(kLoAppMemEnd, kShadowBeg); ProtectRange(kShadowEnd, kMetaShadowBeg); ProtectRange(kMetaShadowEnd, kTraceMemBeg); // Memory for traces is mapped lazily in MapThreadTrace. // Protect the whole range for now, so that user does not map something here. ProtectRange(kTraceMemBeg, kTraceMemEnd); ProtectRange(kTraceMemEnd, kHeapMemBeg); - ProtectRange(kHeapMemEnd + PrimaryAllocator::AdditionalSize(), kHiAppMemBeg); + ProtectRange(HeapEnd(), kHiAppMemBeg); } #endif // #ifndef SANITIZER_GO void InitializePlatform() { DisableCoreDumperIfNecessary(); // Go maps shadow memory lazily and works fine with limited address space. // Unlimited stack is not a problem as well, because the executable // is not compiled with -pie. if (kCppMode) { bool reexec = false; // TSan doesn't play well with unlimited stack size (as stack // overlaps with shadow memory). If we detect unlimited stack size, // we re-exec the program with limited stack size as a best effort. if (StackSizeIsUnlimited()) { const uptr kMaxStackSize = 32 * 1024 * 1024; VReport(1, "Program is run with unlimited stack size, which wouldn't " "work with ThreadSanitizer.\n" "Re-execing with stack size limited to %zd bytes.\n", kMaxStackSize); SetStackSizeLimitInBytes(kMaxStackSize); reexec = true; } if (!AddressSpaceIsUnlimited()) { Report("WARNING: Program is run with limited virtual address space," " which wouldn't work with ThreadSanitizer.\n"); Report("Re-execing with unlimited virtual address space.\n"); SetAddressSpaceUnlimited(); reexec = true; } if (reexec) ReExec(); } #ifndef SANITIZER_GO CheckAndProtect(); InitTlsSize(); InitDataSeg(); #endif } bool IsGlobalVar(uptr addr) { return g_data_start && addr >= g_data_start && addr < g_data_end; } #ifndef SANITIZER_GO // Extract file descriptors passed to glibc internal __res_iclose function. // This is required to properly "close" the fds, because we do not see internal // closes within glibc. The code is a pure hack. int ExtractResolvFDs(void *state, int *fds, int nfd) { #if SANITIZER_LINUX int cnt = 0; __res_state *statp = (__res_state*)state; for (int i = 0; i < MAXNS && cnt < nfd; i++) { if (statp->_u._ext.nsaddrs[i] && statp->_u._ext.nssocks[i] != -1) fds[cnt++] = statp->_u._ext.nssocks[i]; } return cnt; #else return 0; #endif } // Extract file descriptors passed via UNIX domain sockets. // This is requried to properly handle "open" of these fds. // see 'man recvmsg' and 'man 3 cmsg'. int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) { int res = 0; msghdr *msg = (msghdr*)msgp; struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); for (; cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) continue; int n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(fds[0]); for (int i = 0; i < n; i++) { fds[res++] = ((int*)CMSG_DATA(cmsg))[i]; if (res == nfd) return res; } } return res; } int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m, void *abstime), void *c, void *m, void *abstime, void(*cleanup)(void *arg), void *arg) { // pthread_cleanup_push/pop are hardcore macros mess. // We can't intercept nor call them w/o including pthread.h. int res; pthread_cleanup_push(cleanup, arg); res = fn(c, m, abstime); pthread_cleanup_pop(0); return res; } #endif } // namespace __tsan #endif // SANITIZER_LINUX || SANITIZER_FREEBSD Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_report.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_report.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_report.cc (revision 279194) @@ -1,412 +1,413 @@ //===-- tsan_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 ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// #include "tsan_report.h" #include "tsan_platform.h" #include "tsan_rtl.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_report_decorator.h" #include "sanitizer_common/sanitizer_stacktrace_printer.h" namespace __tsan { ReportStack::ReportStack() : frames(nullptr), suppressable(false) {} ReportStack *ReportStack::New() { void *mem = internal_alloc(MBlockReportStack, sizeof(ReportStack)); return new(mem) ReportStack(); } ReportLocation::ReportLocation(ReportLocationType type) : type(type), global(), heap_chunk_start(0), heap_chunk_size(0), tid(0), fd(0), suppressable(false), stack(nullptr) {} ReportLocation *ReportLocation::New(ReportLocationType type) { void *mem = internal_alloc(MBlockReportStack, sizeof(ReportLocation)); return new(mem) ReportLocation(type); } class Decorator: public __sanitizer::SanitizerCommonDecorator { public: Decorator() : SanitizerCommonDecorator() { } const char *Warning() { return Red(); } const char *EndWarning() { return Default(); } const char *Access() { return Blue(); } const char *EndAccess() { return Default(); } const char *ThreadDescription() { return Cyan(); } const char *EndThreadDescription() { return Default(); } const char *Location() { return Green(); } const char *EndLocation() { return Default(); } const char *Sleep() { return Yellow(); } const char *EndSleep() { return Default(); } const char *Mutex() { return Magenta(); } const char *EndMutex() { return Default(); } }; ReportDesc::ReportDesc() : stacks(MBlockReportStack) , mops(MBlockReportMop) , locs(MBlockReportLoc) , mutexes(MBlockReportMutex) , threads(MBlockReportThread) , unique_tids(MBlockReportThread) , sleep() , count() { } ReportMop::ReportMop() : mset(MBlockReportMutex) { } ReportDesc::~ReportDesc() { // FIXME(dvyukov): it must be leaking a lot of memory. } #ifndef SANITIZER_GO const int kThreadBufSize = 32; const char *thread_name(char *buf, int tid) { if (tid == 0) return "main thread"; internal_snprintf(buf, kThreadBufSize, "thread T%d", tid); return buf; } static const char *ReportTypeString(ReportType typ) { if (typ == ReportTypeRace) return "data race"; if (typ == ReportTypeVptrRace) return "data race on vptr (ctor/dtor vs virtual call)"; if (typ == ReportTypeUseAfterFree) return "heap-use-after-free"; if (typ == ReportTypeVptrUseAfterFree) return "heap-use-after-free (virtual call vs free)"; if (typ == ReportTypeThreadLeak) return "thread leak"; if (typ == ReportTypeMutexDestroyLocked) return "destroy of a locked mutex"; if (typ == ReportTypeMutexDoubleLock) return "double lock of a mutex"; if (typ == ReportTypeMutexBadUnlock) return "unlock of an unlocked mutex (or by a wrong thread)"; if (typ == ReportTypeMutexBadReadLock) return "read lock of a write locked mutex"; if (typ == ReportTypeMutexBadReadUnlock) return "read unlock of a write locked mutex"; if (typ == ReportTypeSignalUnsafe) return "signal-unsafe call inside of a signal"; if (typ == ReportTypeErrnoInSignal) return "signal handler spoils errno"; if (typ == ReportTypeDeadlock) return "lock-order-inversion (potential deadlock)"; return ""; } void PrintStack(const ReportStack *ent) { if (ent == 0 || ent->frames == 0) { Printf(" [failed to restore the stack]\n\n"); return; } SymbolizedStack *frame = ent->frames; for (int i = 0; frame && frame->info.address; frame = frame->next, i++) { InternalScopedString res(2 * GetPageSizeCached()); RenderFrame(&res, common_flags()->stack_trace_format, i, frame->info, common_flags()->strip_path_prefix, "__interceptor_"); Printf("%s\n", res.data()); } Printf("\n"); } static void PrintMutexSet(Vector const& mset) { for (uptr i = 0; i < mset.Size(); i++) { if (i == 0) Printf(" (mutexes:"); const ReportMopMutex m = mset[i]; Printf(" %s M%llu", m.write ? "write" : "read", m.id); Printf(i == mset.Size() - 1 ? ")" : ","); } } static const char *MopDesc(bool first, bool write, bool atomic) { return atomic ? (first ? (write ? "Atomic write" : "Atomic read") : (write ? "Previous atomic write" : "Previous atomic read")) : (first ? (write ? "Write" : "Read") : (write ? "Previous write" : "Previous read")); } static void PrintMop(const ReportMop *mop, bool first) { Decorator d; char thrbuf[kThreadBufSize]; Printf("%s", d.Access()); Printf(" %s of size %d at %p by %s", MopDesc(first, mop->write, mop->atomic), mop->size, (void*)mop->addr, thread_name(thrbuf, mop->tid)); PrintMutexSet(mop->mset); Printf(":\n"); Printf("%s", d.EndAccess()); PrintStack(mop->stack); } static void PrintLocation(const ReportLocation *loc) { Decorator d; char thrbuf[kThreadBufSize]; bool print_stack = false; Printf("%s", d.Location()); if (loc->type == ReportLocationGlobal) { const DataInfo &global = loc->global; Printf(" Location is global '%s' of size %zu at %p (%s+%p)\n\n", global.name, global.size, global.start, StripModuleName(global.module), global.module_offset); } else if (loc->type == ReportLocationHeap) { char thrbuf[kThreadBufSize]; Printf(" Location is heap block of size %zu at %p allocated by %s:\n", loc->heap_chunk_size, loc->heap_chunk_start, thread_name(thrbuf, loc->tid)); print_stack = true; } else if (loc->type == ReportLocationStack) { Printf(" Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid)); } else if (loc->type == ReportLocationTLS) { Printf(" Location is TLS of %s.\n\n", thread_name(thrbuf, loc->tid)); } else if (loc->type == ReportLocationFD) { Printf(" Location is file descriptor %d created by %s at:\n", loc->fd, thread_name(thrbuf, loc->tid)); print_stack = true; } Printf("%s", d.EndLocation()); if (print_stack) PrintStack(loc->stack); } static void PrintMutexShort(const ReportMutex *rm, const char *after) { Decorator d; Printf("%sM%zd%s%s", d.Mutex(), rm->id, d.EndMutex(), after); } static void PrintMutexShortWithAddress(const ReportMutex *rm, const char *after) { Decorator d; Printf("%sM%zd (%p)%s%s", d.Mutex(), rm->id, rm->addr, d.EndMutex(), after); } static void PrintMutex(const ReportMutex *rm) { Decorator d; if (rm->destroyed) { Printf("%s", d.Mutex()); Printf(" Mutex M%llu is already destroyed.\n\n", rm->id); Printf("%s", d.EndMutex()); } else { Printf("%s", d.Mutex()); Printf(" Mutex M%llu (%p) created at:\n", rm->id, rm->addr); Printf("%s", d.EndMutex()); PrintStack(rm->stack); } } static void PrintThread(const ReportThread *rt) { Decorator d; if (rt->id == 0) // Little sense in describing the main thread. return; Printf("%s", d.ThreadDescription()); Printf(" Thread T%d", rt->id); if (rt->name && rt->name[0] != '\0') Printf(" '%s'", rt->name); char thrbuf[kThreadBufSize]; Printf(" (tid=%zu, %s) created by %s", rt->pid, rt->running ? "running" : "finished", thread_name(thrbuf, rt->parent_tid)); if (rt->stack) Printf(" at:"); Printf("\n"); Printf("%s", d.EndThreadDescription()); PrintStack(rt->stack); } static void PrintSleep(const ReportStack *s) { Decorator d; Printf("%s", d.Sleep()); Printf(" As if synchronized via sleep:\n"); Printf("%s", d.EndSleep()); PrintStack(s); } static ReportStack *ChooseSummaryStack(const ReportDesc *rep) { if (rep->mops.Size()) return rep->mops[0]->stack; if (rep->stacks.Size()) return rep->stacks[0]; if (rep->mutexes.Size()) return rep->mutexes[0]->stack; if (rep->threads.Size()) return rep->threads[0]->stack; return 0; } static bool FrameIsInternal(const SymbolizedStack *frame) { if (frame == 0) return false; const char *file = frame->info.file; return file != 0 && (internal_strstr(file, "tsan_interceptors.cc") || internal_strstr(file, "sanitizer_common_interceptors.inc") || internal_strstr(file, "tsan_interface_")); } static SymbolizedStack *SkipTsanInternalFrames(SymbolizedStack *frames) { while (FrameIsInternal(frames) && frames->next) frames = frames->next; return frames; } void PrintReport(const ReportDesc *rep) { Decorator d; Printf("==================\n"); const char *rep_typ_str = ReportTypeString(rep->typ); Printf("%s", d.Warning()); Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str, (int)internal_getpid()); Printf("%s", d.EndWarning()); if (rep->typ == ReportTypeDeadlock) { char thrbuf[kThreadBufSize]; Printf(" Cycle in lock order graph: "); for (uptr i = 0; i < rep->mutexes.Size(); i++) PrintMutexShortWithAddress(rep->mutexes[i], " => "); PrintMutexShort(rep->mutexes[0], "\n\n"); CHECK_GT(rep->mutexes.Size(), 0U); CHECK_EQ(rep->mutexes.Size() * (flags()->second_deadlock_stack ? 2 : 1), rep->stacks.Size()); for (uptr i = 0; i < rep->mutexes.Size(); i++) { Printf(" Mutex "); PrintMutexShort(rep->mutexes[(i + 1) % rep->mutexes.Size()], " acquired here while holding mutex "); PrintMutexShort(rep->mutexes[i], " in "); Printf("%s", d.ThreadDescription()); Printf("%s:\n", thread_name(thrbuf, rep->unique_tids[i])); Printf("%s", d.EndThreadDescription()); if (flags()->second_deadlock_stack) { PrintStack(rep->stacks[2*i]); Printf(" Mutex "); PrintMutexShort(rep->mutexes[i], " previously acquired by the same thread here:\n"); PrintStack(rep->stacks[2*i+1]); } else { PrintStack(rep->stacks[i]); if (i == 0) Printf(" Hint: use TSAN_OPTIONS=second_deadlock_stack=1 " "to get more informative warning message\n\n"); } } } else { for (uptr i = 0; i < rep->stacks.Size(); i++) { if (i) Printf(" and:\n"); PrintStack(rep->stacks[i]); } } for (uptr i = 0; i < rep->mops.Size(); i++) PrintMop(rep->mops[i], i == 0); if (rep->sleep) PrintSleep(rep->sleep); for (uptr i = 0; i < rep->locs.Size(); i++) PrintLocation(rep->locs[i]); if (rep->typ != ReportTypeDeadlock) { for (uptr i = 0; i < rep->mutexes.Size(); i++) PrintMutex(rep->mutexes[i]); } for (uptr i = 0; i < rep->threads.Size(); i++) PrintThread(rep->threads[i]); if (rep->typ == ReportTypeThreadLeak && rep->count > 1) Printf(" And %d more similar thread leaks.\n\n", rep->count - 1); if (ReportStack *stack = ChooseSummaryStack(rep)) { if (SymbolizedStack *frame = SkipTsanInternalFrames(stack->frames)) { const AddressInfo &info = frame->info; ReportErrorSummary(rep_typ_str, info.file, info.line, info.function); } } Printf("==================\n"); } #else // #ifndef SANITIZER_GO const int kMainThreadId = 1; void PrintStack(const ReportStack *ent) { if (ent == 0 || ent->frames == 0) { Printf(" [failed to restore the stack]\n"); return; } SymbolizedStack *frame = ent->frames; for (int i = 0; frame; frame = frame->next, i++) { const AddressInfo &info = frame->info; - Printf(" %s()\n %s:%d +0x%zx\n", info.function, info.file, info.line, - (void *)info.module_offset); + Printf(" %s()\n %s:%d +0x%zx\n", info.function, + StripPathPrefix(info.file, common_flags()->strip_path_prefix), + info.line, (void *)info.module_offset); } } static void PrintMop(const ReportMop *mop, bool first) { Printf("\n"); Printf("%s by ", (first ? (mop->write ? "Write" : "Read") : (mop->write ? "Previous write" : "Previous read"))); if (mop->tid == kMainThreadId) Printf("main goroutine:\n"); else Printf("goroutine %d:\n", mop->tid); PrintStack(mop->stack); } static void PrintThread(const ReportThread *rt) { if (rt->id == kMainThreadId) return; Printf("\n"); Printf("Goroutine %d (%s) created at:\n", rt->id, rt->running ? "running" : "finished"); PrintStack(rt->stack); } void PrintReport(const ReportDesc *rep) { Printf("==================\n"); if (rep->typ == ReportTypeRace) { Printf("WARNING: DATA RACE"); for (uptr i = 0; i < rep->mops.Size(); i++) PrintMop(rep->mops[i], i == 0); for (uptr i = 0; i < rep->threads.Size(); i++) PrintThread(rep->threads[i]); } else if (rep->typ == ReportTypeDeadlock) { Printf("WARNING: DEADLOCK\n"); for (uptr i = 0; i < rep->mutexes.Size(); i++) { Printf("Goroutine %d lock mutex %d while holding mutex %d:\n", 999, rep->mutexes[i]->id, rep->mutexes[(i+1) % rep->mutexes.Size()]->id); PrintStack(rep->stacks[2*i]); Printf("\n"); Printf("Mutex %d was previously locked here:\n", rep->mutexes[(i+1) % rep->mutexes.Size()]->id); PrintStack(rep->stacks[2*i + 1]); Printf("\n"); } } Printf("==================\n"); } #endif } // namespace __tsan Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.cc (revision 279194) @@ -1,993 +1,1006 @@ //===-- tsan_rtl.cc -------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of ThreadSanitizer (TSan), a race detector. // // Main file (entry points) for the TSan run-time. //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_symbolizer.h" #include "tsan_defs.h" #include "tsan_platform.h" #include "tsan_rtl.h" #include "tsan_mman.h" #include "tsan_suppressions.h" #include "tsan_symbolize.h" #ifdef __SSE3__ // transitively includes , // and it's prohibited to include std headers into tsan runtime. // So we do this dirty trick. #define _MM_MALLOC_H_INCLUDED #define __MM_MALLOC_H #include typedef __m128i m128; #endif volatile int __tsan_resumed = 0; extern "C" void __tsan_resume() { __tsan_resumed = 1; } namespace __tsan { #ifndef SANITIZER_GO THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64); #endif static char ctx_placeholder[sizeof(Context)] ALIGNED(64); Context *ctx; // Can be overriden by a front-end. #ifdef TSAN_EXTERNAL_HOOKS bool OnFinalize(bool failed); void OnInitialize(); #else SANITIZER_INTERFACE_ATTRIBUTE bool WEAK OnFinalize(bool failed) { return failed; } SANITIZER_INTERFACE_ATTRIBUTE void WEAK OnInitialize() {} #endif static char thread_registry_placeholder[sizeof(ThreadRegistry)]; static ThreadContextBase *CreateThreadContext(u32 tid) { // Map thread trace when context is created. MapThreadTrace(GetThreadTrace(tid), TraceSize() * sizeof(Event)); - MapThreadTrace(GetThreadTraceHeader(tid), sizeof(Trace)); - new(ThreadTrace(tid)) Trace(); + const uptr hdr = GetThreadTraceHeader(tid); + MapThreadTrace(hdr, sizeof(Trace)); + new((void*)hdr) Trace(); + // We are going to use only a small part of the trace with the default + // value of history_size. However, the constructor writes to the whole trace. + // Unmap the unused part. + uptr hdr_end = hdr + sizeof(Trace); + hdr_end -= sizeof(TraceHeader) * (kTraceParts - TraceParts()); + hdr_end = RoundUp(hdr_end, GetPageSizeCached()); + if (hdr_end < hdr + sizeof(Trace)) + UnmapOrDie((void*)hdr_end, hdr + sizeof(Trace) - hdr_end); void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext)); return new(mem) ThreadContext(tid); } #ifndef SANITIZER_GO static const u32 kThreadQuarantineSize = 16; #else static const u32 kThreadQuarantineSize = 64; #endif Context::Context() : initialized() , report_mtx(MutexTypeReport, StatMtxReport) , nreported() , nmissed_expected() , thread_registry(new(thread_registry_placeholder) ThreadRegistry( CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse)) , racy_stacks(MBlockRacyStacks) , racy_addresses(MBlockRacyAddresses) , fired_suppressions(8) { } // The objects are allocated in TLS, so one may rely on zero-initialization. ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch, unsigned reuse_count, uptr stk_addr, uptr stk_size, uptr tls_addr, uptr tls_size) : fast_state(tid, epoch) // Do not touch these, rely on zero initialization, // they may be accessed before the ctor. // , ignore_reads_and_writes() // , ignore_interceptors() , clock(tid, reuse_count) #ifndef SANITIZER_GO , jmp_bufs(MBlockJmpBuf) #endif , tid(tid) , unique_id(unique_id) , stk_addr(stk_addr) , stk_size(stk_size) , tls_addr(tls_addr) , tls_size(tls_size) #ifndef SANITIZER_GO , last_sleep_clock(tid) #endif { } +#ifndef SANITIZER_GO static void MemoryProfiler(Context *ctx, fd_t fd, int i) { uptr n_threads; uptr n_running_threads; ctx->thread_registry->GetNumberOfThreads(&n_threads, &n_running_threads); InternalScopedBuffer buf(4096); WriteMemoryProfile(buf.data(), buf.size(), n_threads, n_running_threads); internal_write(fd, buf.data(), internal_strlen(buf.data())); } static void BackgroundThread(void *arg) { -#ifndef SANITIZER_GO // This is a non-initialized non-user thread, nothing to see here. // We don't use ScopedIgnoreInterceptors, because we want ignores to be // enabled even when the thread function exits (e.g. during pthread thread // shutdown code). cur_thread()->ignore_interceptors++; -#endif const u64 kMs2Ns = 1000 * 1000; fd_t mprof_fd = kInvalidFd; if (flags()->profile_memory && flags()->profile_memory[0]) { if (internal_strcmp(flags()->profile_memory, "stdout") == 0) { mprof_fd = 1; } else if (internal_strcmp(flags()->profile_memory, "stderr") == 0) { mprof_fd = 2; } else { InternalScopedString filename(kMaxPathLength); filename.append("%s.%d", flags()->profile_memory, (int)internal_getpid()); uptr openrv = OpenFile(filename.data(), true); if (internal_iserror(openrv)) { Printf("ThreadSanitizer: failed to open memory profile file '%s'\n", &filename[0]); } else { mprof_fd = openrv; } } } u64 last_flush = NanoTime(); uptr last_rss = 0; for (int i = 0; atomic_load(&ctx->stop_background_thread, memory_order_relaxed) == 0; i++) { SleepForMillis(100); u64 now = NanoTime(); // Flush memory if requested. if (flags()->flush_memory_ms > 0) { if (last_flush + flags()->flush_memory_ms * kMs2Ns < now) { VPrintf(1, "ThreadSanitizer: periodic memory flush\n"); FlushShadowMemory(); last_flush = NanoTime(); } } // GetRSS can be expensive on huge programs, so don't do it every 100ms. if (flags()->memory_limit_mb > 0) { uptr rss = GetRSS(); uptr limit = uptr(flags()->memory_limit_mb) << 20; VPrintf(1, "ThreadSanitizer: memory flush check" " RSS=%llu LAST=%llu LIMIT=%llu\n", (u64)rss >> 20, (u64)last_rss >> 20, (u64)limit >> 20); if (2 * rss > limit + last_rss) { VPrintf(1, "ThreadSanitizer: flushing memory due to RSS\n"); FlushShadowMemory(); rss = GetRSS(); VPrintf(1, "ThreadSanitizer: memory flushed RSS=%llu\n", (u64)rss>>20); } last_rss = rss; } // Write memory profile if requested. if (mprof_fd != kInvalidFd) MemoryProfiler(ctx, mprof_fd, i); -#ifndef SANITIZER_GO // Flush symbolizer cache if requested. if (flags()->flush_symbolizer_ms > 0) { u64 last = atomic_load(&ctx->last_symbolize_time_ns, memory_order_relaxed); if (last != 0 && last + flags()->flush_symbolizer_ms * kMs2Ns < now) { Lock l(&ctx->report_mtx); SpinMutexLock l2(&CommonSanitizerReportMutex); SymbolizeFlush(); atomic_store(&ctx->last_symbolize_time_ns, 0, memory_order_relaxed); } } -#endif } } static void StartBackgroundThread() { ctx->background_thread = internal_start_thread(&BackgroundThread, 0); } -#ifndef SANITIZER_GO +#ifndef __mips__ static void StopBackgroundThread() { atomic_store(&ctx->stop_background_thread, 1, memory_order_relaxed); internal_join_thread(ctx->background_thread); ctx->background_thread = 0; } #endif +#endif void DontNeedShadowFor(uptr addr, uptr size) { uptr shadow_beg = MemToShadow(addr); uptr shadow_end = MemToShadow(addr + size); FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg); } void MapShadow(uptr addr, uptr size) { // Global data is not 64K aligned, but there are no adjacent mappings, // so we can get away with unaligned mapping. // CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment MmapFixedNoReserve(MemToShadow(addr), size * kShadowMultiplier); // Meta shadow is 2:1, so tread carefully. static bool data_mapped = false; static uptr mapped_meta_end = 0; uptr meta_begin = (uptr)MemToMeta(addr); uptr meta_end = (uptr)MemToMeta(addr + size); meta_begin = RoundDownTo(meta_begin, 64 << 10); meta_end = RoundUpTo(meta_end, 64 << 10); if (!data_mapped) { // First call maps data+bss. data_mapped = true; MmapFixedNoReserve(meta_begin, meta_end - meta_begin); } else { // Mapping continous heap. // Windows wants 64K alignment. meta_begin = RoundDownTo(meta_begin, 64 << 10); meta_end = RoundUpTo(meta_end, 64 << 10); if (meta_end <= mapped_meta_end) return; if (meta_begin < mapped_meta_end) meta_begin = mapped_meta_end; MmapFixedNoReserve(meta_begin, meta_end - meta_begin); mapped_meta_end = meta_end; } VPrintf(2, "mapped meta shadow for (%p-%p) at (%p-%p)\n", addr, addr+size, meta_begin, meta_end); } void MapThreadTrace(uptr addr, uptr size) { DPrintf("#0: Mapping trace at %p-%p(0x%zx)\n", addr, addr + size, size); CHECK_GE(addr, kTraceMemBeg); CHECK_LE(addr + size, kTraceMemEnd); CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment uptr addr1 = (uptr)MmapFixedNoReserve(addr, size); if (addr1 != addr) { Printf("FATAL: ThreadSanitizer can not mmap thread trace (%p/%p->%p)\n", addr, size, addr1); Die(); } } static void CheckShadowMapping() { for (uptr i = 0; i < ARRAY_SIZE(UserRegions); i += 2) { const uptr beg = UserRegions[i]; const uptr end = UserRegions[i + 1]; VPrintf(3, "checking shadow region %p-%p\n", beg, end); for (uptr p0 = beg; p0 <= end; p0 += (end - beg) / 4) { for (int x = -1; x <= 1; x++) { const uptr p = p0 + x; if (p < beg || p >= end) continue; const uptr s = MemToShadow(p); - VPrintf(3, " checking pointer %p -> %p\n", p, s); + const uptr m = (uptr)MemToMeta(p); + VPrintf(3, " checking pointer %p: shadow=%p meta=%p\n", p, s, m); CHECK(IsAppMem(p)); CHECK(IsShadowMem(s)); CHECK_EQ(p & ~(kShadowCell - 1), ShadowToMem(s)); - const uptr m = (uptr)MemToMeta(p); CHECK(IsMetaMem(m)); } } } } void Initialize(ThreadState *thr) { // Thread safe because done before all threads exist. static bool is_initialized = false; if (is_initialized) return; is_initialized = true; // We are not ready to handle interceptors yet. ScopedIgnoreInterceptors ignore; SanitizerToolName = "ThreadSanitizer"; // Install tool-specific callbacks in sanitizer_common. SetCheckFailedCallback(TsanCheckFailed); ctx = new(ctx_placeholder) Context; const char *options = GetEnv(kTsanOptionsEnv); InitializeFlags(&ctx->flags, options); #ifndef SANITIZER_GO InitializeAllocator(); #endif InitializeInterceptors(); CheckShadowMapping(); InitializePlatform(); InitializeMutex(); InitializeDynamicAnnotations(); #ifndef SANITIZER_GO InitializeShadowMemory(); #endif // Setup correct file descriptor for error reports. __sanitizer_set_report_path(common_flags()->log_path); InitializeSuppressions(); #ifndef SANITIZER_GO InitializeLibIgnore(); Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer); -#endif + // On MIPS, TSan initialization is run before + // __pthread_initialize_minimal_internal() is finished, so we can not spawn + // new threads. +#ifndef __mips__ StartBackgroundThread(); -#ifndef SANITIZER_GO SetSandboxingCallback(StopBackgroundThread); #endif +#endif if (common_flags()->detect_deadlocks) ctx->dd = DDetector::Create(flags()); VPrintf(1, "***** Running under ThreadSanitizer v2 (pid %d) *****\n", (int)internal_getpid()); // Initialize thread 0. int tid = ThreadCreate(thr, 0, 0, true); CHECK_EQ(tid, 0); ThreadStart(thr, tid, internal_getpid()); ctx->initialized = true; if (flags()->stop_on_start) { Printf("ThreadSanitizer is suspended at startup (pid %d)." " Call __tsan_resume().\n", (int)internal_getpid()); while (__tsan_resumed == 0) {} } OnInitialize(); } int Finalize(ThreadState *thr) { bool failed = false; if (flags()->atexit_sleep_ms > 0 && ThreadCount(thr) > 1) SleepForMillis(flags()->atexit_sleep_ms); // Wait for pending reports. ctx->report_mtx.Lock(); CommonSanitizerReportMutex.Lock(); CommonSanitizerReportMutex.Unlock(); ctx->report_mtx.Unlock(); #ifndef SANITIZER_GO if (Verbosity()) AllocatorPrintStats(); #endif ThreadFinalize(thr); if (ctx->nreported) { failed = true; #ifndef SANITIZER_GO Printf("ThreadSanitizer: reported %d warnings\n", ctx->nreported); #else Printf("Found %d data race(s)\n", ctx->nreported); #endif } if (ctx->nmissed_expected) { failed = true; Printf("ThreadSanitizer: missed %d expected races\n", ctx->nmissed_expected); } if (common_flags()->print_suppressions) PrintMatchedSuppressions(); #ifndef SANITIZER_GO if (flags()->print_benign) PrintMatchedBenignRaces(); #endif failed = OnFinalize(failed); +#if TSAN_COLLECT_STATS StatAggregate(ctx->stat, thr->stat); StatOutput(ctx->stat); +#endif + return failed ? flags()->exitcode : 0; } #ifndef SANITIZER_GO void ForkBefore(ThreadState *thr, uptr pc) { ctx->thread_registry->Lock(); ctx->report_mtx.Lock(); } void ForkParentAfter(ThreadState *thr, uptr pc) { ctx->report_mtx.Unlock(); ctx->thread_registry->Unlock(); } void ForkChildAfter(ThreadState *thr, uptr pc) { ctx->report_mtx.Unlock(); ctx->thread_registry->Unlock(); uptr nthread = 0; ctx->thread_registry->GetNumberOfThreads(0, 0, &nthread /* alive threads */); VPrintf(1, "ThreadSanitizer: forked new process with pid %d," " parent had %d threads\n", (int)internal_getpid(), (int)nthread); if (nthread == 1) { - internal_start_thread(&BackgroundThread, 0); + StartBackgroundThread(); } else { // We've just forked a multi-threaded process. We cannot reasonably function // after that (some mutexes may be locked before fork). So just enable // ignores for everything in the hope that we will exec soon. ctx->after_multithreaded_fork = true; thr->ignore_interceptors++; ThreadIgnoreBegin(thr, pc); ThreadIgnoreSyncBegin(thr, pc); } } #endif #ifdef SANITIZER_GO NOINLINE void GrowShadowStack(ThreadState *thr) { const int sz = thr->shadow_stack_end - thr->shadow_stack; const int newsz = 2 * sz; uptr *newstack = (uptr*)internal_alloc(MBlockShadowStack, newsz * sizeof(uptr)); internal_memcpy(newstack, thr->shadow_stack, sz * sizeof(uptr)); internal_free(thr->shadow_stack); thr->shadow_stack = newstack; thr->shadow_stack_pos = newstack + sz; thr->shadow_stack_end = newstack + newsz; } #endif u32 CurrentStackId(ThreadState *thr, uptr pc) { if (thr->shadow_stack_pos == 0) // May happen during bootstrap. return 0; if (pc != 0) { #ifndef SANITIZER_GO DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end); #else if (thr->shadow_stack_pos == thr->shadow_stack_end) GrowShadowStack(thr); #endif thr->shadow_stack_pos[0] = pc; thr->shadow_stack_pos++; } u32 id = StackDepotPut( StackTrace(thr->shadow_stack, thr->shadow_stack_pos - thr->shadow_stack)); if (pc != 0) thr->shadow_stack_pos--; return id; } void TraceSwitch(ThreadState *thr) { thr->nomalloc++; Trace *thr_trace = ThreadTrace(thr->tid); Lock l(&thr_trace->mtx); unsigned trace = (thr->fast_state.epoch() / kTracePartSize) % TraceParts(); TraceHeader *hdr = &thr_trace->headers[trace]; hdr->epoch0 = thr->fast_state.epoch(); ObtainCurrentStack(thr, 0, &hdr->stack0); hdr->mset0 = thr->mset; thr->nomalloc--; } Trace *ThreadTrace(int tid) { return (Trace*)GetThreadTraceHeader(tid); } uptr TraceTopPC(ThreadState *thr) { Event *events = (Event*)GetThreadTrace(thr->tid); uptr pc = events[thr->fast_state.GetTracePos()]; return pc; } uptr TraceSize() { return (uptr)(1ull << (kTracePartSizeBits + flags()->history_size + 1)); } uptr TraceParts() { return TraceSize() / kTracePartSize; } #ifndef SANITIZER_GO extern "C" void __tsan_trace_switch() { TraceSwitch(cur_thread()); } extern "C" void __tsan_report_race() { ReportRace(cur_thread()); } #endif ALWAYS_INLINE Shadow LoadShadow(u64 *p) { u64 raw = atomic_load((atomic_uint64_t*)p, memory_order_relaxed); return Shadow(raw); } ALWAYS_INLINE void StoreShadow(u64 *sp, u64 s) { atomic_store((atomic_uint64_t*)sp, s, memory_order_relaxed); } ALWAYS_INLINE void StoreIfNotYetStored(u64 *sp, u64 *s) { StoreShadow(sp, *s); *s = 0; } ALWAYS_INLINE void HandleRace(ThreadState *thr, u64 *shadow_mem, Shadow cur, Shadow old) { thr->racy_state[0] = cur.raw(); thr->racy_state[1] = old.raw(); thr->racy_shadow_addr = shadow_mem; #ifndef SANITIZER_GO HACKY_CALL(__tsan_report_race); #else ReportRace(thr); #endif } static inline bool HappensBefore(Shadow old, ThreadState *thr) { return thr->clock.get(old.TidWithIgnore()) >= old.epoch(); } ALWAYS_INLINE void MemoryAccessImpl1(ThreadState *thr, uptr addr, int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic, u64 *shadow_mem, Shadow cur) { StatInc(thr, StatMop); StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead); StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog)); // This potentially can live in an MMX/SSE scratch register. // The required intrinsics are: // __m128i _mm_move_epi64(__m128i*); // _mm_storel_epi64(u64*, __m128i); u64 store_word = cur.raw(); // scan all the shadow values and dispatch to 4 categories: // same, replace, candidate and race (see comments below). // we consider only 3 cases regarding access sizes: // equal, intersect and not intersect. initially I considered // larger and smaller as well, it allowed to replace some // 'candidates' with 'same' or 'replace', but I think // it's just not worth it (performance- and complexity-wise). Shadow old(0); // It release mode we manually unroll the loop, // because empirically gcc generates better code this way. // However, we can't afford unrolling in debug mode, because the function // consumes almost 4K of stack. Gtest gives only 4K of stack to death test // threads, which is not enough for the unrolled loop. #if SANITIZER_DEBUG for (int idx = 0; idx < 4; idx++) { #include "tsan_update_shadow_word_inl.h" } #else int idx = 0; #include "tsan_update_shadow_word_inl.h" idx = 1; #include "tsan_update_shadow_word_inl.h" idx = 2; #include "tsan_update_shadow_word_inl.h" idx = 3; #include "tsan_update_shadow_word_inl.h" #endif // we did not find any races and had already stored // the current access info, so we are done if (LIKELY(store_word == 0)) return; // choose a random candidate slot and replace it StoreShadow(shadow_mem + (cur.epoch() % kShadowCnt), store_word); StatInc(thr, StatShadowReplace); return; RACE: HandleRace(thr, shadow_mem, cur, old); return; } void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr, int size, bool kAccessIsWrite, bool kIsAtomic) { while (size) { int size1 = 1; int kAccessSizeLog = kSizeLog1; if (size >= 8 && (addr & ~7) == ((addr + 7) & ~7)) { size1 = 8; kAccessSizeLog = kSizeLog8; } else if (size >= 4 && (addr & ~7) == ((addr + 3) & ~7)) { size1 = 4; kAccessSizeLog = kSizeLog4; } else if (size >= 2 && (addr & ~7) == ((addr + 1) & ~7)) { size1 = 2; kAccessSizeLog = kSizeLog2; } MemoryAccess(thr, pc, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic); addr += size1; size -= size1; } } ALWAYS_INLINE bool ContainsSameAccessSlow(u64 *s, u64 a, u64 sync_epoch, bool is_write) { Shadow cur(a); for (uptr i = 0; i < kShadowCnt; i++) { Shadow old(LoadShadow(&s[i])); if (Shadow::Addr0AndSizeAreEqual(cur, old) && old.TidWithIgnore() == cur.TidWithIgnore() && old.epoch() > sync_epoch && old.IsAtomic() == cur.IsAtomic() && old.IsRead() <= cur.IsRead()) return true; } return false; } #if defined(__SSE3__) #define SHUF(v0, v1, i0, i1, i2, i3) _mm_castps_si128(_mm_shuffle_ps( \ _mm_castsi128_ps(v0), _mm_castsi128_ps(v1), \ (i0)*1 + (i1)*4 + (i2)*16 + (i3)*64)) ALWAYS_INLINE bool ContainsSameAccessFast(u64 *s, u64 a, u64 sync_epoch, bool is_write) { // This is an optimized version of ContainsSameAccessSlow. // load current access into access[0:63] const m128 access = _mm_cvtsi64_si128(a); // duplicate high part of access in addr0: // addr0[0:31] = access[32:63] // addr0[32:63] = access[32:63] // addr0[64:95] = access[32:63] // addr0[96:127] = access[32:63] const m128 addr0 = SHUF(access, access, 1, 1, 1, 1); // load 4 shadow slots const m128 shadow0 = _mm_load_si128((__m128i*)s); const m128 shadow1 = _mm_load_si128((__m128i*)s + 1); // load high parts of 4 shadow slots into addr_vect: // addr_vect[0:31] = shadow0[32:63] // addr_vect[32:63] = shadow0[96:127] // addr_vect[64:95] = shadow1[32:63] // addr_vect[96:127] = shadow1[96:127] m128 addr_vect = SHUF(shadow0, shadow1, 1, 3, 1, 3); if (!is_write) { // set IsRead bit in addr_vect const m128 rw_mask1 = _mm_cvtsi64_si128(1<<15); const m128 rw_mask = SHUF(rw_mask1, rw_mask1, 0, 0, 0, 0); addr_vect = _mm_or_si128(addr_vect, rw_mask); } // addr0 == addr_vect? const m128 addr_res = _mm_cmpeq_epi32(addr0, addr_vect); // epoch1[0:63] = sync_epoch const m128 epoch1 = _mm_cvtsi64_si128(sync_epoch); // epoch[0:31] = sync_epoch[0:31] // epoch[32:63] = sync_epoch[0:31] // epoch[64:95] = sync_epoch[0:31] // epoch[96:127] = sync_epoch[0:31] const m128 epoch = SHUF(epoch1, epoch1, 0, 0, 0, 0); // load low parts of shadow cell epochs into epoch_vect: // epoch_vect[0:31] = shadow0[0:31] // epoch_vect[32:63] = shadow0[64:95] // epoch_vect[64:95] = shadow1[0:31] // epoch_vect[96:127] = shadow1[64:95] const m128 epoch_vect = SHUF(shadow0, shadow1, 0, 2, 0, 2); // epoch_vect >= sync_epoch? const m128 epoch_res = _mm_cmpgt_epi32(epoch_vect, epoch); // addr_res & epoch_res const m128 res = _mm_and_si128(addr_res, epoch_res); // mask[0] = res[7] // mask[1] = res[15] // ... // mask[15] = res[127] const int mask = _mm_movemask_epi8(res); return mask != 0; } #endif ALWAYS_INLINE bool ContainsSameAccess(u64 *s, u64 a, u64 sync_epoch, bool is_write) { #if defined(__SSE3__) bool res = ContainsSameAccessFast(s, a, sync_epoch, is_write); // NOTE: this check can fail if the shadow is concurrently mutated // by other threads. But it still can be useful if you modify // ContainsSameAccessFast and want to ensure that it's not completely broken. // DCHECK_EQ(res, ContainsSameAccessSlow(s, a, sync_epoch, is_write)); return res; #else return ContainsSameAccessSlow(s, a, sync_epoch, is_write); #endif } ALWAYS_INLINE USED void MemoryAccess(ThreadState *thr, uptr pc, uptr addr, int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic) { u64 *shadow_mem = (u64*)MemToShadow(addr); DPrintf2("#%d: MemoryAccess: @%p %p size=%d" " is_write=%d shadow_mem=%p {%zx, %zx, %zx, %zx}\n", (int)thr->fast_state.tid(), (void*)pc, (void*)addr, (int)(1 << kAccessSizeLog), kAccessIsWrite, shadow_mem, (uptr)shadow_mem[0], (uptr)shadow_mem[1], (uptr)shadow_mem[2], (uptr)shadow_mem[3]); #if SANITIZER_DEBUG if (!IsAppMem(addr)) { Printf("Access to non app mem %zx\n", addr); DCHECK(IsAppMem(addr)); } if (!IsShadowMem((uptr)shadow_mem)) { Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr); DCHECK(IsShadowMem((uptr)shadow_mem)); } #endif if (kCppMode && *shadow_mem == kShadowRodata) { // Access to .rodata section, no races here. // Measurements show that it can be 10-20% of all memory accesses. StatInc(thr, StatMop); StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead); StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog)); StatInc(thr, StatMopRodata); return; } FastState fast_state = thr->fast_state; if (fast_state.GetIgnoreBit()) { StatInc(thr, StatMop); StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead); StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog)); StatInc(thr, StatMopIgnored); return; } Shadow cur(fast_state); cur.SetAddr0AndSizeLog(addr & 7, kAccessSizeLog); cur.SetWrite(kAccessIsWrite); cur.SetAtomic(kIsAtomic); if (LIKELY(ContainsSameAccess(shadow_mem, cur.raw(), thr->fast_synch_epoch, kAccessIsWrite))) { StatInc(thr, StatMop); StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead); StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog)); StatInc(thr, StatMopSame); return; } if (kCollectHistory) { fast_state.IncrementEpoch(); thr->fast_state = fast_state; TraceAddEvent(thr, fast_state, EventTypeMop, pc); cur.IncrementEpoch(); } MemoryAccessImpl1(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic, shadow_mem, cur); } // Called by MemoryAccessRange in tsan_rtl_thread.cc ALWAYS_INLINE USED void MemoryAccessImpl(ThreadState *thr, uptr addr, int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic, u64 *shadow_mem, Shadow cur) { if (LIKELY(ContainsSameAccess(shadow_mem, cur.raw(), thr->fast_synch_epoch, kAccessIsWrite))) { StatInc(thr, StatMop); StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead); StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog)); StatInc(thr, StatMopSame); return; } MemoryAccessImpl1(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic, shadow_mem, cur); } static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size, u64 val) { (void)thr; (void)pc; if (size == 0) return; // FIXME: fix me. uptr offset = addr % kShadowCell; if (offset) { offset = kShadowCell - offset; if (size <= offset) return; addr += offset; size -= offset; } DCHECK_EQ(addr % 8, 0); // If a user passes some insane arguments (memset(0)), // let it just crash as usual. if (!IsAppMem(addr) || !IsAppMem(addr + size - 1)) return; // Don't want to touch lots of shadow memory. // If a program maps 10MB stack, there is no need reset the whole range. size = (size + (kShadowCell - 1)) & ~(kShadowCell - 1); // UnmapOrDie/MmapFixedNoReserve does not work on Windows, // so we do it only for C/C++. if (kGoMode || size < common_flags()->clear_shadow_mmap_threshold) { u64 *p = (u64*)MemToShadow(addr); CHECK(IsShadowMem((uptr)p)); CHECK(IsShadowMem((uptr)(p + size * kShadowCnt / kShadowCell - 1))); // FIXME: may overwrite a part outside the region for (uptr i = 0; i < size / kShadowCell * kShadowCnt;) { p[i++] = val; for (uptr j = 1; j < kShadowCnt; j++) p[i++] = 0; } } else { // The region is big, reset only beginning and end. - const uptr kPageSize = 4096; + const uptr kPageSize = GetPageSizeCached(); u64 *begin = (u64*)MemToShadow(addr); u64 *end = begin + size / kShadowCell * kShadowCnt; u64 *p = begin; // Set at least first kPageSize/2 to page boundary. while ((p < begin + kPageSize / kShadowSize / 2) || ((uptr)p % kPageSize)) { *p++ = val; for (uptr j = 1; j < kShadowCnt; j++) *p++ = 0; } // Reset middle part. u64 *p1 = p; p = RoundDown(end, kPageSize); UnmapOrDie((void*)p1, (uptr)p - (uptr)p1); MmapFixedNoReserve((uptr)p1, (uptr)p - (uptr)p1); // Set the ending. while (p < end) { *p++ = val; for (uptr j = 1; j < kShadowCnt; j++) *p++ = 0; } } } void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size) { MemoryRangeSet(thr, pc, addr, size, 0); } void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size) { // Processing more than 1k (4k of shadow) is expensive, // can cause excessive memory consumption (user does not necessary touch // the whole range) and most likely unnecessary. if (size > 1024) size = 1024; CHECK_EQ(thr->is_freeing, false); thr->is_freeing = true; MemoryAccessRange(thr, pc, addr, size, true); thr->is_freeing = false; if (kCollectHistory) { thr->fast_state.IncrementEpoch(); TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc); } Shadow s(thr->fast_state); s.ClearIgnoreBit(); s.MarkAsFreed(); s.SetWrite(true); s.SetAddr0AndSizeLog(0, 3); MemoryRangeSet(thr, pc, addr, size, s.raw()); } void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size) { if (kCollectHistory) { thr->fast_state.IncrementEpoch(); TraceAddEvent(thr, thr->fast_state, EventTypeMop, pc); } Shadow s(thr->fast_state); s.ClearIgnoreBit(); s.SetWrite(true); s.SetAddr0AndSizeLog(0, 3); MemoryRangeSet(thr, pc, addr, size, s.raw()); } ALWAYS_INLINE USED void FuncEntry(ThreadState *thr, uptr pc) { StatInc(thr, StatFuncEnter); DPrintf2("#%d: FuncEntry %p\n", (int)thr->fast_state.tid(), (void*)pc); if (kCollectHistory) { thr->fast_state.IncrementEpoch(); TraceAddEvent(thr, thr->fast_state, EventTypeFuncEnter, pc); } // Shadow stack maintenance can be replaced with // stack unwinding during trace switch (which presumably must be faster). DCHECK_GE(thr->shadow_stack_pos, thr->shadow_stack); #ifndef SANITIZER_GO DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end); #else if (thr->shadow_stack_pos == thr->shadow_stack_end) GrowShadowStack(thr); #endif thr->shadow_stack_pos[0] = pc; thr->shadow_stack_pos++; } ALWAYS_INLINE USED void FuncExit(ThreadState *thr) { StatInc(thr, StatFuncExit); DPrintf2("#%d: FuncExit\n", (int)thr->fast_state.tid()); if (kCollectHistory) { thr->fast_state.IncrementEpoch(); TraceAddEvent(thr, thr->fast_state, EventTypeFuncExit, 0); } DCHECK_GT(thr->shadow_stack_pos, thr->shadow_stack); #ifndef SANITIZER_GO DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end); #endif thr->shadow_stack_pos--; } void ThreadIgnoreBegin(ThreadState *thr, uptr pc) { DPrintf("#%d: ThreadIgnoreBegin\n", thr->tid); thr->ignore_reads_and_writes++; CHECK_GT(thr->ignore_reads_and_writes, 0); thr->fast_state.SetIgnoreBit(); #ifndef SANITIZER_GO if (!ctx->after_multithreaded_fork) thr->mop_ignore_set.Add(CurrentStackId(thr, pc)); #endif } void ThreadIgnoreEnd(ThreadState *thr, uptr pc) { DPrintf("#%d: ThreadIgnoreEnd\n", thr->tid); thr->ignore_reads_and_writes--; CHECK_GE(thr->ignore_reads_and_writes, 0); if (thr->ignore_reads_and_writes == 0) { thr->fast_state.ClearIgnoreBit(); #ifndef SANITIZER_GO thr->mop_ignore_set.Reset(); #endif } } void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc) { DPrintf("#%d: ThreadIgnoreSyncBegin\n", thr->tid); thr->ignore_sync++; CHECK_GT(thr->ignore_sync, 0); #ifndef SANITIZER_GO if (!ctx->after_multithreaded_fork) thr->sync_ignore_set.Add(CurrentStackId(thr, pc)); #endif } void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc) { DPrintf("#%d: ThreadIgnoreSyncEnd\n", thr->tid); thr->ignore_sync--; CHECK_GE(thr->ignore_sync, 0); #ifndef SANITIZER_GO if (thr->ignore_sync == 0) thr->sync_ignore_set.Reset(); #endif } bool MD5Hash::operator==(const MD5Hash &other) const { return hash[0] == other.hash[0] && hash[1] == other.hash[1]; } #if SANITIZER_DEBUG void build_consistency_debug() {} #else void build_consistency_release() {} #endif #if TSAN_COLLECT_STATS void build_consistency_stats() {} #else void build_consistency_nostats() {} #endif } // namespace __tsan #ifndef SANITIZER_GO // Must be included in this file to make sure everything is inlined. #include "tsan_interface_inl.h" #endif Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl.h (revision 279194) @@ -1,734 +1,766 @@ //===-- tsan_rtl.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. // // Main internal TSan header file. // // Ground rules: // - C++ run-time should not be used (static CTORs, RTTI, exceptions, static // function-scope locals) // - All functions/classes/etc reside in namespace __tsan, except for those // declared in tsan_interface.h. // - Platform-specific files should be used instead of ifdefs (*). // - No system headers included in header files (*). // - Platform specific headres included only into platform-specific files (*). // // (*) Except when inlining is critical for performance. //===----------------------------------------------------------------------===// #ifndef TSAN_RTL_H #define TSAN_RTL_H #include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_asm.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_deadlock_detector_interface.h" #include "sanitizer_common/sanitizer_libignore.h" #include "sanitizer_common/sanitizer_suppressions.h" #include "sanitizer_common/sanitizer_thread_registry.h" #include "tsan_clock.h" #include "tsan_defs.h" #include "tsan_flags.h" #include "tsan_sync.h" #include "tsan_trace.h" #include "tsan_vector.h" #include "tsan_report.h" #include "tsan_platform.h" #include "tsan_mutexset.h" #include "tsan_ignoreset.h" #include "tsan_stack_trace.h" #if SANITIZER_WORDSIZE != 64 # error "ThreadSanitizer is supported only on 64-bit platforms" #endif namespace __tsan { #ifndef SANITIZER_GO struct MapUnmapCallback; +#ifdef __mips64 +static const uptr kAllocatorSpace = 0; +static const uptr kAllocatorSize = SANITIZER_MMAP_RANGE_SIZE; +static const uptr kAllocatorRegionSizeLog = 20; +static const uptr kAllocatorNumRegions = + kAllocatorSize >> kAllocatorRegionSizeLog; +typedef TwoLevelByteMap<(kAllocatorNumRegions >> 12), 1 << 12, + MapUnmapCallback> ByteMap; +typedef SizeClassAllocator32 PrimaryAllocator; +#else typedef SizeClassAllocator64 PrimaryAllocator; +#endif typedef SizeClassAllocatorLocalCache AllocatorCache; typedef LargeMmapAllocator SecondaryAllocator; typedef CombinedAllocator Allocator; Allocator *allocator(); #endif void TsanCheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2); const u64 kShadowRodata = (u64)-1; // .rodata shadow marker // FastState (from most significant bit): // ignore : 1 // tid : kTidBits // unused : - // history_size : 3 // epoch : kClkBits class FastState { public: FastState(u64 tid, u64 epoch) { x_ = tid << kTidShift; x_ |= epoch; DCHECK_EQ(tid, this->tid()); DCHECK_EQ(epoch, this->epoch()); DCHECK_EQ(GetIgnoreBit(), false); } explicit FastState(u64 x) : x_(x) { } u64 raw() const { return x_; } u64 tid() const { u64 res = (x_ & ~kIgnoreBit) >> kTidShift; return res; } u64 TidWithIgnore() const { u64 res = x_ >> kTidShift; return res; } u64 epoch() const { u64 res = x_ & ((1ull << kClkBits) - 1); return res; } void IncrementEpoch() { u64 old_epoch = epoch(); x_ += 1; DCHECK_EQ(old_epoch + 1, epoch()); (void)old_epoch; } void SetIgnoreBit() { x_ |= kIgnoreBit; } void ClearIgnoreBit() { x_ &= ~kIgnoreBit; } bool GetIgnoreBit() const { return (s64)x_ < 0; } void SetHistorySize(int hs) { CHECK_GE(hs, 0); CHECK_LE(hs, 7); x_ = (x_ & ~(kHistoryMask << kHistoryShift)) | (u64(hs) << kHistoryShift); } ALWAYS_INLINE int GetHistorySize() const { return (int)((x_ >> kHistoryShift) & kHistoryMask); } void ClearHistorySize() { SetHistorySize(0); } ALWAYS_INLINE u64 GetTracePos() const { const int hs = GetHistorySize(); // When hs == 0, the trace consists of 2 parts. const u64 mask = (1ull << (kTracePartSizeBits + hs + 1)) - 1; return epoch() & mask; } private: friend class Shadow; static const int kTidShift = 64 - kTidBits - 1; static const u64 kIgnoreBit = 1ull << 63; static const u64 kFreedBit = 1ull << 63; static const u64 kHistoryShift = kClkBits; static const u64 kHistoryMask = 7; u64 x_; }; // Shadow (from most significant bit): // freed : 1 // tid : kTidBits // is_atomic : 1 // is_read : 1 // size_log : 2 // addr0 : 3 // epoch : kClkBits class Shadow : public FastState { public: explicit Shadow(u64 x) : FastState(x) { } explicit Shadow(const FastState &s) : FastState(s.x_) { ClearHistorySize(); } void SetAddr0AndSizeLog(u64 addr0, unsigned kAccessSizeLog) { DCHECK_EQ((x_ >> kClkBits) & 31, 0); DCHECK_LE(addr0, 7); DCHECK_LE(kAccessSizeLog, 3); x_ |= ((kAccessSizeLog << 3) | addr0) << kClkBits; DCHECK_EQ(kAccessSizeLog, size_log()); DCHECK_EQ(addr0, this->addr0()); } void SetWrite(unsigned kAccessIsWrite) { DCHECK_EQ(x_ & kReadBit, 0); if (!kAccessIsWrite) x_ |= kReadBit; DCHECK_EQ(kAccessIsWrite, IsWrite()); } void SetAtomic(bool kIsAtomic) { DCHECK(!IsAtomic()); if (kIsAtomic) x_ |= kAtomicBit; DCHECK_EQ(IsAtomic(), kIsAtomic); } bool IsAtomic() const { return x_ & kAtomicBit; } bool IsZero() const { return x_ == 0; } static inline bool TidsAreEqual(const Shadow s1, const Shadow s2) { u64 shifted_xor = (s1.x_ ^ s2.x_) >> kTidShift; DCHECK_EQ(shifted_xor == 0, s1.TidWithIgnore() == s2.TidWithIgnore()); return shifted_xor == 0; } static ALWAYS_INLINE bool Addr0AndSizeAreEqual(const Shadow s1, const Shadow s2) { u64 masked_xor = ((s1.x_ ^ s2.x_) >> kClkBits) & 31; return masked_xor == 0; } static ALWAYS_INLINE bool TwoRangesIntersect(Shadow s1, Shadow s2, unsigned kS2AccessSize) { bool res = false; u64 diff = s1.addr0() - s2.addr0(); if ((s64)diff < 0) { // s1.addr0 < s2.addr0 // NOLINT // if (s1.addr0() + size1) > s2.addr0()) return true; if (s1.size() > -diff) res = true; } else { // if (s2.addr0() + kS2AccessSize > s1.addr0()) return true; if (kS2AccessSize > diff) res = true; } DCHECK_EQ(res, TwoRangesIntersectSlow(s1, s2)); DCHECK_EQ(res, TwoRangesIntersectSlow(s2, s1)); return res; } u64 ALWAYS_INLINE addr0() const { return (x_ >> kClkBits) & 7; } u64 ALWAYS_INLINE size() const { return 1ull << size_log(); } bool ALWAYS_INLINE IsWrite() const { return !IsRead(); } bool ALWAYS_INLINE IsRead() const { return x_ & kReadBit; } // The idea behind the freed bit is as follows. // When the memory is freed (or otherwise unaccessible) we write to the shadow // values with tid/epoch related to the free and the freed bit set. // During memory accesses processing the freed bit is considered // as msb of tid. So any access races with shadow with freed bit set // (it is as if write from a thread with which we never synchronized before). // This allows us to detect accesses to freed memory w/o additional // overheads in memory access processing and at the same time restore // tid/epoch of free. void MarkAsFreed() { x_ |= kFreedBit; } bool IsFreed() const { return x_ & kFreedBit; } bool GetFreedAndReset() { bool res = x_ & kFreedBit; x_ &= ~kFreedBit; return res; } bool ALWAYS_INLINE IsBothReadsOrAtomic(bool kIsWrite, bool kIsAtomic) const { bool v = x_ & ((u64(kIsWrite ^ 1) << kReadShift) | (u64(kIsAtomic) << kAtomicShift)); DCHECK_EQ(v, (!IsWrite() && !kIsWrite) || (IsAtomic() && kIsAtomic)); return v; } bool ALWAYS_INLINE IsRWNotWeaker(bool kIsWrite, bool kIsAtomic) const { bool v = ((x_ >> kReadShift) & 3) <= u64((kIsWrite ^ 1) | (kIsAtomic << 1)); DCHECK_EQ(v, (IsAtomic() < kIsAtomic) || (IsAtomic() == kIsAtomic && !IsWrite() <= !kIsWrite)); return v; } bool ALWAYS_INLINE IsRWWeakerOrEqual(bool kIsWrite, bool kIsAtomic) const { bool v = ((x_ >> kReadShift) & 3) >= u64((kIsWrite ^ 1) | (kIsAtomic << 1)); DCHECK_EQ(v, (IsAtomic() > kIsAtomic) || (IsAtomic() == kIsAtomic && !IsWrite() >= !kIsWrite)); return v; } private: static const u64 kReadShift = 5 + kClkBits; static const u64 kReadBit = 1ull << kReadShift; static const u64 kAtomicShift = 6 + kClkBits; static const u64 kAtomicBit = 1ull << kAtomicShift; u64 size_log() const { return (x_ >> (3 + kClkBits)) & 3; } static bool TwoRangesIntersectSlow(const Shadow s1, const Shadow s2) { if (s1.addr0() == s2.addr0()) return true; if (s1.addr0() < s2.addr0() && s1.addr0() + s1.size() > s2.addr0()) return true; if (s2.addr0() < s1.addr0() && s2.addr0() + s2.size() > s1.addr0()) return true; return false; } }; struct SignalContext; struct JmpBuf { uptr sp; uptr mangled_sp; int int_signal_send; bool in_blocking_func; uptr in_signal_handler; uptr *shadow_stack_pos; }; // This struct is stored in TLS. struct ThreadState { FastState fast_state; // Synch epoch represents the threads's epoch before the last synchronization // action. It allows to reduce number of shadow state updates. // For example, fast_synch_epoch=100, last write to addr X was at epoch=150, // if we are processing write to X from the same thread at epoch=200, // we do nothing, because both writes happen in the same 'synch epoch'. // That is, if another memory access does not race with the former write, // it does not race with the latter as well. // QUESTION: can we can squeeze this into ThreadState::Fast? // E.g. ThreadState::Fast is a 44-bit, 32 are taken by synch_epoch and 12 are // taken by epoch between synchs. // This way we can save one load from tls. u64 fast_synch_epoch; // This is a slow path flag. On fast path, fast_state.GetIgnoreBit() is read. // We do not distinguish beteween ignoring reads and writes // for better performance. int ignore_reads_and_writes; int ignore_sync; // Go does not support ignores. #ifndef SANITIZER_GO IgnoreSet mop_ignore_set; IgnoreSet sync_ignore_set; #endif // C/C++ uses fixed size shadow stack embed into Trace. // Go uses malloc-allocated shadow stack with dynamic size. uptr *shadow_stack; uptr *shadow_stack_end; uptr *shadow_stack_pos; u64 *racy_shadow_addr; u64 racy_state[2]; MutexSet mset; ThreadClock clock; #ifndef SANITIZER_GO AllocatorCache alloc_cache; InternalAllocatorCache internal_alloc_cache; Vector jmp_bufs; int ignore_interceptors; #endif +#if TSAN_COLLECT_STATS u64 stat[StatCnt]; +#endif const int tid; const int unique_id; bool in_symbolizer; bool in_ignored_lib; bool is_dead; bool is_freeing; bool is_vptr_access; const uptr stk_addr; const uptr stk_size; const uptr tls_addr; const uptr tls_size; ThreadContext *tctx; +#if SANITIZER_DEBUG && !SANITIZER_GO InternalDeadlockDetector internal_deadlock_detector; +#endif DDPhysicalThread *dd_pt; DDLogicalThread *dd_lt; atomic_uintptr_t in_signal_handler; SignalContext *signal_ctx; DenseSlabAllocCache block_cache; DenseSlabAllocCache sync_cache; DenseSlabAllocCache clock_cache; #ifndef SANITIZER_GO u32 last_sleep_stack_id; ThreadClock last_sleep_clock; #endif // Set in regions of runtime that must be signal-safe and fork-safe. // If set, malloc must not be called. int nomalloc; explicit ThreadState(Context *ctx, int tid, int unique_id, u64 epoch, unsigned reuse_count, uptr stk_addr, uptr stk_size, uptr tls_addr, uptr tls_size); }; #ifndef SANITIZER_GO __attribute__((tls_model("initial-exec"))) extern THREADLOCAL char cur_thread_placeholder[]; INLINE ThreadState *cur_thread() { return reinterpret_cast(&cur_thread_placeholder); } #endif class ThreadContext : public ThreadContextBase { public: explicit ThreadContext(int tid); ~ThreadContext(); ThreadState *thr; u32 creation_stack_id; SyncClock sync; // Epoch at which the thread had started. // If we see an event from the thread stamped by an older epoch, // the event is from a dead thread that shared tid with this thread. u64 epoch0; u64 epoch1; // Override superclass callbacks. void OnDead(); void OnJoined(void *arg); void OnFinished(); void OnStarted(void *arg); void OnCreated(void *arg); void OnReset(); void OnDetached(void *arg); }; struct RacyStacks { MD5Hash hash[2]; bool operator==(const RacyStacks &other) const { if (hash[0] == other.hash[0] && hash[1] == other.hash[1]) return true; if (hash[0] == other.hash[1] && hash[1] == other.hash[0]) return true; return false; } }; struct RacyAddress { uptr addr_min; uptr addr_max; }; struct FiredSuppression { ReportType type; uptr pc; Suppression *supp; }; struct Context { Context(); bool initialized; bool after_multithreaded_fork; MetaMap metamap; Mutex report_mtx; int nreported; int nmissed_expected; atomic_uint64_t last_symbolize_time_ns; void *background_thread; atomic_uint32_t stop_background_thread; ThreadRegistry *thread_registry; Vector racy_stacks; Vector racy_addresses; // Number of fired suppressions may be large enough. InternalMmapVector fired_suppressions; DDetector *dd; ClockAlloc clock_alloc; Flags flags; u64 stat[StatCnt]; u64 int_alloc_cnt[MBlockTypeCount]; u64 int_alloc_siz[MBlockTypeCount]; }; extern Context *ctx; // The one and the only global runtime context. struct ScopedIgnoreInterceptors { ScopedIgnoreInterceptors() { #ifndef SANITIZER_GO cur_thread()->ignore_interceptors++; #endif } ~ScopedIgnoreInterceptors() { #ifndef SANITIZER_GO cur_thread()->ignore_interceptors--; #endif } }; class ScopedReport { public: explicit ScopedReport(ReportType typ); ~ScopedReport(); void AddMemoryAccess(uptr addr, Shadow s, StackTrace stack, const MutexSet *mset); void AddStack(StackTrace stack, bool suppressable = false); void AddThread(const ThreadContext *tctx, bool suppressable = false); void AddThread(int unique_tid, bool suppressable = false); void AddUniqueTid(int unique_tid); void AddMutex(const SyncVar *s); u64 AddMutex(u64 id); void AddLocation(uptr addr, uptr size); void AddSleep(u32 stack_id); void SetCount(int count); const ReportDesc *GetReport() const; private: ReportDesc *rep_; // Symbolizer makes lots of intercepted calls. If we try to process them, // at best it will cause deadlocks on internal mutexes. ScopedIgnoreInterceptors ignore_interceptors_; void AddDeadMutex(u64 id); ScopedReport(const ScopedReport&); void operator = (const ScopedReport&); }; void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk, MutexSet *mset); template void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack) { uptr size = thr->shadow_stack_pos - thr->shadow_stack; uptr start = 0; if (size + !!toppc > kStackTraceMax) { start = size + !!toppc - kStackTraceMax; size = kStackTraceMax - !!toppc; } stack->Init(&thr->shadow_stack[start], size, toppc); } +#if TSAN_COLLECT_STATS void StatAggregate(u64 *dst, u64 *src); void StatOutput(u64 *stat); +#endif + void ALWAYS_INLINE StatInc(ThreadState *thr, StatType typ, u64 n = 1) { - if (kCollectStats) - thr->stat[typ] += n; +#if TSAN_COLLECT_STATS + thr->stat[typ] += n; +#endif } void ALWAYS_INLINE StatSet(ThreadState *thr, StatType typ, u64 n) { - if (kCollectStats) - thr->stat[typ] = n; +#if TSAN_COLLECT_STATS + thr->stat[typ] = n; +#endif } void MapShadow(uptr addr, uptr size); void MapThreadTrace(uptr addr, uptr size); void DontNeedShadowFor(uptr addr, uptr size); void InitializeShadowMemory(); void InitializeInterceptors(); void InitializeLibIgnore(); void InitializeDynamicAnnotations(); void ForkBefore(ThreadState *thr, uptr pc); void ForkParentAfter(ThreadState *thr, uptr pc); void ForkChildAfter(ThreadState *thr, uptr pc); void ReportRace(ThreadState *thr); bool OutputReport(ThreadState *thr, const ScopedReport &srep); bool IsFiredSuppression(Context *ctx, const ScopedReport &srep, StackTrace trace); bool IsExpectedReport(uptr addr, uptr size); void PrintMatchedBenignRaces(); #if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1 # define DPrintf Printf #else # define DPrintf(...) #endif #if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 2 # define DPrintf2 Printf #else # define DPrintf2(...) #endif u32 CurrentStackId(ThreadState *thr, uptr pc); ReportStack *SymbolizeStackId(u32 stack_id); void PrintCurrentStack(ThreadState *thr, uptr pc); void PrintCurrentStackSlow(uptr pc); // uses libunwind void Initialize(ThreadState *thr); int Finalize(ThreadState *thr); void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write); void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write); void MemoryAccess(ThreadState *thr, uptr pc, uptr addr, int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic); void MemoryAccessImpl(ThreadState *thr, uptr addr, int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic, u64 *shadow_mem, Shadow cur); void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, uptr size, bool is_write); void MemoryAccessRangeStep(ThreadState *thr, uptr pc, uptr addr, uptr size, uptr step, bool is_write); void UnalignedMemoryAccess(ThreadState *thr, uptr pc, uptr addr, int size, bool kAccessIsWrite, bool kIsAtomic); const int kSizeLog1 = 0; const int kSizeLog2 = 1; const int kSizeLog4 = 2; const int kSizeLog8 = 3; void ALWAYS_INLINE MemoryRead(ThreadState *thr, uptr pc, uptr addr, int kAccessSizeLog) { MemoryAccess(thr, pc, addr, kAccessSizeLog, false, false); } void ALWAYS_INLINE MemoryWrite(ThreadState *thr, uptr pc, uptr addr, int kAccessSizeLog) { MemoryAccess(thr, pc, addr, kAccessSizeLog, true, false); } void ALWAYS_INLINE MemoryReadAtomic(ThreadState *thr, uptr pc, uptr addr, int kAccessSizeLog) { MemoryAccess(thr, pc, addr, kAccessSizeLog, false, true); } void ALWAYS_INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc, uptr addr, int kAccessSizeLog) { MemoryAccess(thr, pc, addr, kAccessSizeLog, true, true); } void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size); void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size); void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size); void ThreadIgnoreBegin(ThreadState *thr, uptr pc); void ThreadIgnoreEnd(ThreadState *thr, uptr pc); void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc); void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc); void FuncEntry(ThreadState *thr, uptr pc); void FuncExit(ThreadState *thr); int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached); void ThreadStart(ThreadState *thr, int tid, uptr os_id); void ThreadFinish(ThreadState *thr); int ThreadTid(ThreadState *thr, uptr pc, uptr uid); void ThreadJoin(ThreadState *thr, uptr pc, int tid); void ThreadDetach(ThreadState *thr, uptr pc, int tid); void ThreadFinalize(ThreadState *thr); void ThreadSetName(ThreadState *thr, const char *name); int ThreadCount(ThreadState *thr); void ProcessPendingSignals(ThreadState *thr); void MutexCreate(ThreadState *thr, uptr pc, uptr addr, bool rw, bool recursive, bool linker_init); void MutexDestroy(ThreadState *thr, uptr pc, uptr addr); void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec = 1, bool try_lock = false); int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all = false); void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool try_lock = false); void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr); void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr); void MutexRepair(ThreadState *thr, uptr pc, uptr addr); // call on EOWNERDEAD void Acquire(ThreadState *thr, uptr pc, uptr addr); // AcquireGlobal synchronizes the current thread with all other threads. // In terms of happens-before relation, it draws a HB edge from all threads // (where they happen to execute right now) to the current thread. We use it to // handle Go finalizers. Namely, finalizer goroutine executes AcquireGlobal // right before executing finalizers. This provides a coarse, but simple // approximation of the actual required synchronization. void AcquireGlobal(ThreadState *thr, uptr pc); void Release(ThreadState *thr, uptr pc, uptr addr); void ReleaseStore(ThreadState *thr, uptr pc, uptr addr); void AfterSleep(ThreadState *thr, uptr pc); void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c); void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c); void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c); void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c); // The hacky call uses custom calling convention and an assembly thunk. // It is considerably faster that a normal call for the caller // if it is not executed (it is intended for slow paths from hot functions). // The trick is that the call preserves all registers and the compiler // does not treat it as a call. // If it does not work for you, use normal call. #if !SANITIZER_DEBUG && defined(__x86_64__) // The caller may not create the stack frame for itself at all, // so we create a reserve stack frame for it (1024b must be enough). #define HACKY_CALL(f) \ __asm__ __volatile__("sub $1024, %%rsp;" \ CFI_INL_ADJUST_CFA_OFFSET(1024) \ ".hidden " #f "_thunk;" \ "call " #f "_thunk;" \ "add $1024, %%rsp;" \ CFI_INL_ADJUST_CFA_OFFSET(-1024) \ ::: "memory", "cc"); #else #define HACKY_CALL(f) f() #endif void TraceSwitch(ThreadState *thr); uptr TraceTopPC(ThreadState *thr); uptr TraceSize(); uptr TraceParts(); Trace *ThreadTrace(int tid); extern "C" void __tsan_trace_switch(); void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs, EventType typ, u64 addr) { if (!kCollectHistory) return; DCHECK_GE((int)typ, 0); DCHECK_LE((int)typ, 7); DCHECK_EQ(GetLsb(addr, 61), addr); StatInc(thr, StatEvents); u64 pos = fs.GetTracePos(); if (UNLIKELY((pos % kTracePartSize) == 0)) { #ifndef SANITIZER_GO HACKY_CALL(__tsan_trace_switch); #else TraceSwitch(thr); #endif } Event *trace = (Event*)GetThreadTrace(fs.tid()); Event *evp = &trace[pos]; Event ev = (u64)addr | ((u64)typ << 61); *evp = ev; } + +#ifndef SANITIZER_GO +uptr ALWAYS_INLINE HeapEnd() { +#if SANITIZER_CAN_USE_ALLOCATOR64 + return kHeapMemEnd + PrimaryAllocator::AdditionalSize(); +#else + return kHeapMemEnd; +#endif +} +#endif } // namespace __tsan #endif // TSAN_RTL_H Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc (revision 279194) @@ -1,693 +1,687 @@ //===-- tsan_rtl_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 ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "tsan_platform.h" #include "tsan_rtl.h" #include "tsan_suppressions.h" #include "tsan_symbolize.h" #include "tsan_report.h" #include "tsan_sync.h" #include "tsan_mman.h" #include "tsan_flags.h" #include "tsan_fd.h" namespace __tsan { using namespace __sanitizer; // NOLINT static ReportStack *SymbolizeStack(StackTrace trace); void TsanCheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2) { // There is high probability that interceptors will check-fail as well, // on the other hand there is no sense in processing interceptors // since we are going to die soon. ScopedIgnoreInterceptors ignore; Printf("FATAL: ThreadSanitizer CHECK failed: " "%s:%d \"%s\" (0x%zx, 0x%zx)\n", file, line, cond, (uptr)v1, (uptr)v2); PrintCurrentStackSlow(StackTrace::GetCurrentPc()); Die(); } // Can be overriden by an application/test to intercept reports. #ifdef TSAN_EXTERNAL_HOOKS bool OnReport(const ReportDesc *rep, bool suppressed); #else SANITIZER_INTERFACE_ATTRIBUTE bool WEAK OnReport(const ReportDesc *rep, bool suppressed) { (void)rep; return suppressed; } #endif static void StackStripMain(SymbolizedStack *frames) { SymbolizedStack *last_frame = nullptr; SymbolizedStack *last_frame2 = nullptr; for (SymbolizedStack *cur = frames; cur; cur = cur->next) { last_frame2 = last_frame; last_frame = cur; } if (last_frame2 == 0) return; #ifndef SANITIZER_GO const char *last = last_frame->info.function; const char *last2 = last_frame2->info.function; // Strip frame above 'main' if (last2 && 0 == internal_strcmp(last2, "main")) { last_frame->ClearAll(); last_frame2->next = nullptr; // Strip our internal thread start routine. } else if (last && 0 == internal_strcmp(last, "__tsan_thread_start_func")) { last_frame->ClearAll(); last_frame2->next = nullptr; // Strip global ctors init. } else if (last && 0 == internal_strcmp(last, "__do_global_ctors_aux")) { last_frame->ClearAll(); last_frame2->next = nullptr; // If both are 0, then we probably just failed to symbolize. } else if (last || last2) { // Ensure that we recovered stack completely. Trimmed stack // can actually happen if we do not instrument some code, // so it's only a debug print. However we must try hard to not miss it // due to our fault. DPrintf("Bottom stack frame is missed\n"); } #else // The last frame always point into runtime (gosched0, goexit0, runtime.main). last_frame->ClearAll(); last_frame2->next = nullptr; #endif } ReportStack *SymbolizeStackId(u32 stack_id) { if (stack_id == 0) return 0; StackTrace stack = StackDepotGet(stack_id); if (stack.trace == nullptr) return nullptr; return SymbolizeStack(stack); } static ReportStack *SymbolizeStack(StackTrace trace) { if (trace.size == 0) return 0; SymbolizedStack *top = nullptr; for (uptr si = 0; si < trace.size; si++) { const uptr pc = trace.trace[si]; uptr pc1 = pc; -#ifndef SANITIZER_GO // We obtain the return address, but we're interested in the previous // instruction. if ((pc & kExternalPCBit) == 0) pc1 = StackTrace::GetPreviousInstructionPc(pc); -#else - // FIXME(dvyukov): Go sometimes uses address of a function as top pc. - if (si != trace.size - 1) - pc1 -= 1; -#endif SymbolizedStack *ent = SymbolizeCode(pc1); CHECK_NE(ent, 0); SymbolizedStack *last = ent; while (last->next) { last->info.address = pc; // restore original pc for report last = last->next; } last->info.address = pc; // restore original pc for report last->next = top; top = ent; } StackStripMain(top); ReportStack *stack = ReportStack::New(); stack->frames = top; return stack; } ScopedReport::ScopedReport(ReportType typ) { ctx->thread_registry->CheckLocked(); void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc)); rep_ = new(mem) ReportDesc; rep_->typ = typ; ctx->report_mtx.Lock(); CommonSanitizerReportMutex.Lock(); } ScopedReport::~ScopedReport() { CommonSanitizerReportMutex.Unlock(); ctx->report_mtx.Unlock(); DestroyAndFree(rep_); } void ScopedReport::AddStack(StackTrace stack, bool suppressable) { ReportStack **rs = rep_->stacks.PushBack(); *rs = SymbolizeStack(stack); (*rs)->suppressable = suppressable; } void ScopedReport::AddMemoryAccess(uptr addr, Shadow s, StackTrace stack, const MutexSet *mset) { void *mem = internal_alloc(MBlockReportMop, sizeof(ReportMop)); ReportMop *mop = new(mem) ReportMop; rep_->mops.PushBack(mop); mop->tid = s.tid(); mop->addr = addr + s.addr0(); mop->size = s.size(); mop->write = s.IsWrite(); mop->atomic = s.IsAtomic(); mop->stack = SymbolizeStack(stack); if (mop->stack) mop->stack->suppressable = true; for (uptr i = 0; i < mset->Size(); i++) { MutexSet::Desc d = mset->Get(i); u64 mid = this->AddMutex(d.id); ReportMopMutex mtx = {mid, d.write}; mop->mset.PushBack(mtx); } } void ScopedReport::AddUniqueTid(int unique_tid) { rep_->unique_tids.PushBack(unique_tid); } void ScopedReport::AddThread(const ThreadContext *tctx, bool suppressable) { for (uptr i = 0; i < rep_->threads.Size(); i++) { if ((u32)rep_->threads[i]->id == tctx->tid) return; } void *mem = internal_alloc(MBlockReportThread, sizeof(ReportThread)); ReportThread *rt = new(mem) ReportThread(); rep_->threads.PushBack(rt); rt->id = tctx->tid; rt->pid = tctx->os_id; rt->running = (tctx->status == ThreadStatusRunning); rt->name = internal_strdup(tctx->name); rt->parent_tid = tctx->parent_tid; rt->stack = 0; rt->stack = SymbolizeStackId(tctx->creation_stack_id); if (rt->stack) rt->stack->suppressable = suppressable; } #ifndef SANITIZER_GO static ThreadContext *FindThreadByUidLocked(int unique_id) { ctx->thread_registry->CheckLocked(); for (unsigned i = 0; i < kMaxTid; i++) { ThreadContext *tctx = static_cast( ctx->thread_registry->GetThreadLocked(i)); if (tctx && tctx->unique_id == (u32)unique_id) { return tctx; } } return 0; } static ThreadContext *FindThreadByTidLocked(int tid) { ctx->thread_registry->CheckLocked(); return static_cast( ctx->thread_registry->GetThreadLocked(tid)); } static bool IsInStackOrTls(ThreadContextBase *tctx_base, void *arg) { uptr addr = (uptr)arg; ThreadContext *tctx = static_cast(tctx_base); if (tctx->status != ThreadStatusRunning) return false; ThreadState *thr = tctx->thr; CHECK(thr); return ((addr >= thr->stk_addr && addr < thr->stk_addr + thr->stk_size) || (addr >= thr->tls_addr && addr < thr->tls_addr + thr->tls_size)); } ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack) { ctx->thread_registry->CheckLocked(); ThreadContext *tctx = static_cast( ctx->thread_registry->FindThreadContextLocked(IsInStackOrTls, (void*)addr)); if (!tctx) return 0; ThreadState *thr = tctx->thr; CHECK(thr); *is_stack = (addr >= thr->stk_addr && addr < thr->stk_addr + thr->stk_size); return tctx; } #endif void ScopedReport::AddThread(int unique_tid, bool suppressable) { #ifndef SANITIZER_GO if (const ThreadContext *tctx = FindThreadByUidLocked(unique_tid)) AddThread(tctx, suppressable); #endif } void ScopedReport::AddMutex(const SyncVar *s) { for (uptr i = 0; i < rep_->mutexes.Size(); i++) { if (rep_->mutexes[i]->id == s->uid) return; } void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex)); ReportMutex *rm = new(mem) ReportMutex(); rep_->mutexes.PushBack(rm); rm->id = s->uid; rm->addr = s->addr; rm->destroyed = false; rm->stack = SymbolizeStackId(s->creation_stack_id); } u64 ScopedReport::AddMutex(u64 id) { u64 uid = 0; u64 mid = id; uptr addr = SyncVar::SplitId(id, &uid); SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr); // Check that the mutex is still alive. // Another mutex can be created at the same address, // so check uid as well. if (s && s->CheckId(uid)) { mid = s->uid; AddMutex(s); } else { AddDeadMutex(id); } if (s) s->mtx.Unlock(); return mid; } void ScopedReport::AddDeadMutex(u64 id) { for (uptr i = 0; i < rep_->mutexes.Size(); i++) { if (rep_->mutexes[i]->id == id) return; } void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex)); ReportMutex *rm = new(mem) ReportMutex(); rep_->mutexes.PushBack(rm); rm->id = id; rm->addr = 0; rm->destroyed = true; rm->stack = 0; } void ScopedReport::AddLocation(uptr addr, uptr size) { if (addr == 0) return; #ifndef SANITIZER_GO int fd = -1; int creat_tid = -1; u32 creat_stack = 0; if (FdLocation(addr, &fd, &creat_tid, &creat_stack)) { ReportLocation *loc = ReportLocation::New(ReportLocationFD); loc->fd = fd; loc->tid = creat_tid; loc->stack = SymbolizeStackId(creat_stack); rep_->locs.PushBack(loc); ThreadContext *tctx = FindThreadByUidLocked(creat_tid); if (tctx) AddThread(tctx); return; } MBlock *b = 0; Allocator *a = allocator(); if (a->PointerIsMine((void*)addr)) { void *block_begin = a->GetBlockBegin((void*)addr); if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin); } if (b != 0) { ThreadContext *tctx = FindThreadByTidLocked(b->tid); ReportLocation *loc = ReportLocation::New(ReportLocationHeap); loc->heap_chunk_start = (uptr)allocator()->GetBlockBegin((void *)addr); loc->heap_chunk_size = b->siz; loc->tid = tctx ? tctx->tid : b->tid; loc->stack = SymbolizeStackId(b->stk); rep_->locs.PushBack(loc); if (tctx) AddThread(tctx); return; } bool is_stack = false; if (ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack)) { ReportLocation *loc = ReportLocation::New(is_stack ? ReportLocationStack : ReportLocationTLS); loc->tid = tctx->tid; rep_->locs.PushBack(loc); AddThread(tctx); } if (ReportLocation *loc = SymbolizeData(addr)) { loc->suppressable = true; rep_->locs.PushBack(loc); return; } #endif } #ifndef SANITIZER_GO void ScopedReport::AddSleep(u32 stack_id) { rep_->sleep = SymbolizeStackId(stack_id); } #endif void ScopedReport::SetCount(int count) { rep_->count = count; } const ReportDesc *ScopedReport::GetReport() const { return rep_; } void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk, MutexSet *mset) { // This function restores stack trace and mutex set for the thread/epoch. // It does so by getting stack trace and mutex set at the beginning of // trace part, and then replaying the trace till the given epoch. ctx->thread_registry->CheckLocked(); ThreadContext *tctx = static_cast( ctx->thread_registry->GetThreadLocked(tid)); if (tctx == 0) return; if (tctx->status != ThreadStatusRunning && tctx->status != ThreadStatusFinished && tctx->status != ThreadStatusDead) return; Trace* trace = ThreadTrace(tctx->tid); Lock l(&trace->mtx); const int partidx = (epoch / kTracePartSize) % TraceParts(); TraceHeader* hdr = &trace->headers[partidx]; if (epoch < hdr->epoch0) return; const u64 epoch0 = RoundDown(epoch, TraceSize()); const u64 eend = epoch % TraceSize(); const u64 ebegin = RoundDown(eend, kTracePartSize); DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n", tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx); InternalScopedBuffer stack(kShadowStackSize); for (uptr i = 0; i < hdr->stack0.size; i++) { stack[i] = hdr->stack0.trace[i]; DPrintf2(" #%02zu: pc=%zx\n", i, stack[i]); } if (mset) *mset = hdr->mset0; uptr pos = hdr->stack0.size; Event *events = (Event*)GetThreadTrace(tid); for (uptr i = ebegin; i <= eend; i++) { Event ev = events[i]; EventType typ = (EventType)(ev >> 61); uptr pc = (uptr)(ev & ((1ull << 61) - 1)); DPrintf2(" %zu typ=%d pc=%zx\n", i, typ, pc); if (typ == EventTypeMop) { stack[pos] = pc; } else if (typ == EventTypeFuncEnter) { stack[pos++] = pc; } else if (typ == EventTypeFuncExit) { if (pos > 0) pos--; } if (mset) { if (typ == EventTypeLock) { mset->Add(pc, true, epoch0 + i); } else if (typ == EventTypeUnlock) { mset->Del(pc, true); } else if (typ == EventTypeRLock) { mset->Add(pc, false, epoch0 + i); } else if (typ == EventTypeRUnlock) { mset->Del(pc, false); } } for (uptr j = 0; j <= pos; j++) DPrintf2(" #%zu: %zx\n", j, stack[j]); } if (pos == 0 && stack[0] == 0) return; pos++; stk->Init(stack.data(), pos); } static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2], uptr addr_min, uptr addr_max) { bool equal_stack = false; RacyStacks hash; if (flags()->suppress_equal_stacks) { hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr)); hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr)); for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) { if (hash == ctx->racy_stacks[i]) { DPrintf("ThreadSanitizer: suppressing report as doubled (stack)\n"); equal_stack = true; break; } } } bool equal_address = false; RacyAddress ra0 = {addr_min, addr_max}; if (flags()->suppress_equal_addresses) { for (uptr i = 0; i < ctx->racy_addresses.Size(); i++) { RacyAddress ra2 = ctx->racy_addresses[i]; uptr maxbeg = max(ra0.addr_min, ra2.addr_min); uptr minend = min(ra0.addr_max, ra2.addr_max); if (maxbeg < minend) { DPrintf("ThreadSanitizer: suppressing report as doubled (addr)\n"); equal_address = true; break; } } } if (equal_stack || equal_address) { if (!equal_stack) ctx->racy_stacks.PushBack(hash); if (!equal_address) ctx->racy_addresses.PushBack(ra0); return true; } return false; } static void AddRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2], uptr addr_min, uptr addr_max) { if (flags()->suppress_equal_stacks) { RacyStacks hash; hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr)); hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr)); ctx->racy_stacks.PushBack(hash); } if (flags()->suppress_equal_addresses) { RacyAddress ra0 = {addr_min, addr_max}; ctx->racy_addresses.PushBack(ra0); } } bool OutputReport(ThreadState *thr, const ScopedReport &srep) { atomic_store(&ctx->last_symbolize_time_ns, NanoTime(), memory_order_relaxed); const ReportDesc *rep = srep.GetReport(); Suppression *supp = 0; uptr suppress_pc = 0; for (uptr i = 0; suppress_pc == 0 && i < rep->mops.Size(); i++) suppress_pc = IsSuppressed(rep->typ, rep->mops[i]->stack, &supp); for (uptr i = 0; suppress_pc == 0 && i < rep->stacks.Size(); i++) suppress_pc = IsSuppressed(rep->typ, rep->stacks[i], &supp); for (uptr i = 0; suppress_pc == 0 && i < rep->threads.Size(); i++) suppress_pc = IsSuppressed(rep->typ, rep->threads[i]->stack, &supp); for (uptr i = 0; suppress_pc == 0 && i < rep->locs.Size(); i++) suppress_pc = IsSuppressed(rep->typ, rep->locs[i], &supp); if (suppress_pc != 0) { FiredSuppression s = {srep.GetReport()->typ, suppress_pc, supp}; ctx->fired_suppressions.push_back(s); } { bool old_is_freeing = thr->is_freeing; thr->is_freeing = false; bool suppressed = OnReport(rep, suppress_pc != 0); thr->is_freeing = old_is_freeing; if (suppressed) return false; } PrintReport(rep); ctx->nreported++; if (flags()->halt_on_error) internal__exit(flags()->exitcode); return true; } bool IsFiredSuppression(Context *ctx, const ScopedReport &srep, StackTrace trace) { for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) { if (ctx->fired_suppressions[k].type != srep.GetReport()->typ) continue; for (uptr j = 0; j < trace.size; j++) { FiredSuppression *s = &ctx->fired_suppressions[k]; if (trace.trace[j] == s->pc) { if (s->supp) s->supp->hit_count++; return true; } } } return false; } static bool IsFiredSuppression(Context *ctx, const ScopedReport &srep, uptr addr) { for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) { if (ctx->fired_suppressions[k].type != srep.GetReport()->typ) continue; FiredSuppression *s = &ctx->fired_suppressions[k]; if (addr == s->pc) { if (s->supp) s->supp->hit_count++; return true; } } return false; } static bool RaceBetweenAtomicAndFree(ThreadState *thr) { Shadow s0(thr->racy_state[0]); Shadow s1(thr->racy_state[1]); CHECK(!(s0.IsAtomic() && s1.IsAtomic())); if (!s0.IsAtomic() && !s1.IsAtomic()) return true; if (s0.IsAtomic() && s1.IsFreed()) return true; if (s1.IsAtomic() && thr->is_freeing) return true; return false; } void ReportRace(ThreadState *thr) { CheckNoLocks(thr); // Symbolizer makes lots of intercepted calls. If we try to process them, // at best it will cause deadlocks on internal mutexes. ScopedIgnoreInterceptors ignore; if (!flags()->report_bugs) return; if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr)) return; bool freed = false; { Shadow s(thr->racy_state[1]); freed = s.GetFreedAndReset(); thr->racy_state[1] = s.raw(); } uptr addr = ShadowToMem((uptr)thr->racy_shadow_addr); uptr addr_min = 0; uptr addr_max = 0; { uptr a0 = addr + Shadow(thr->racy_state[0]).addr0(); uptr a1 = addr + Shadow(thr->racy_state[1]).addr0(); uptr e0 = a0 + Shadow(thr->racy_state[0]).size(); uptr e1 = a1 + Shadow(thr->racy_state[1]).size(); addr_min = min(a0, a1); addr_max = max(e0, e1); if (IsExpectedReport(addr_min, addr_max - addr_min)) return; } ThreadRegistryLock l0(ctx->thread_registry); ReportType typ = ReportTypeRace; if (thr->is_vptr_access && freed) typ = ReportTypeVptrUseAfterFree; else if (thr->is_vptr_access) typ = ReportTypeVptrRace; else if (freed) typ = ReportTypeUseAfterFree; ScopedReport rep(typ); if (IsFiredSuppression(ctx, rep, addr)) return; const uptr kMop = 2; VarSizeStackTrace traces[kMop]; const uptr toppc = TraceTopPC(thr); ObtainCurrentStack(thr, toppc, &traces[0]); if (IsFiredSuppression(ctx, rep, traces[0])) return; InternalScopedBuffer mset2(1); new(mset2.data()) MutexSet(); Shadow s2(thr->racy_state[1]); RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2.data()); if (IsFiredSuppression(ctx, rep, traces[1])) return; if (HandleRacyStacks(thr, traces, addr_min, addr_max)) return; for (uptr i = 0; i < kMop; i++) { Shadow s(thr->racy_state[i]); rep.AddMemoryAccess(addr, s, traces[i], i == 0 ? &thr->mset : mset2.data()); } for (uptr i = 0; i < kMop; i++) { FastState s(thr->racy_state[i]); ThreadContext *tctx = static_cast( ctx->thread_registry->GetThreadLocked(s.tid())); if (s.epoch() < tctx->epoch0 || s.epoch() > tctx->epoch1) continue; rep.AddThread(tctx); } rep.AddLocation(addr_min, addr_max - addr_min); #ifndef SANITIZER_GO { // NOLINT Shadow s(thr->racy_state[1]); if (s.epoch() <= thr->last_sleep_clock.get(s.tid())) rep.AddSleep(thr->last_sleep_stack_id); } #endif if (!OutputReport(thr, rep)) return; AddRacyStacks(thr, traces, addr_min, addr_max); } void PrintCurrentStack(ThreadState *thr, uptr pc) { VarSizeStackTrace trace; ObtainCurrentStack(thr, pc, &trace); PrintStack(SymbolizeStack(trace)); } void PrintCurrentStackSlow(uptr pc) { #ifndef SANITIZER_GO BufferedStackTrace *ptrace = new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace))) BufferedStackTrace(); ptrace->Unwind(kStackTraceMax, pc, 0, 0, 0, 0, false); for (uptr i = 0; i < ptrace->size / 2; i++) { uptr tmp = ptrace->trace_buffer[i]; ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1]; ptrace->trace_buffer[ptrace->size - i - 1] = tmp; } PrintStack(SymbolizeStack(*ptrace)); #endif } } // namespace __tsan using namespace __tsan; extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_print_stack_trace() { PrintCurrentStackSlow(StackTrace::GetCurrentPc()); } } // extern "C" Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc (revision 279194) @@ -1,404 +1,408 @@ //===-- tsan_rtl_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 ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_placement_new.h" #include "tsan_rtl.h" #include "tsan_mman.h" #include "tsan_platform.h" #include "tsan_report.h" #include "tsan_sync.h" namespace __tsan { // ThreadContext implementation. ThreadContext::ThreadContext(int tid) : ThreadContextBase(tid) , thr() , sync() , epoch0() , epoch1() { } #ifndef SANITIZER_GO ThreadContext::~ThreadContext() { } #endif void ThreadContext::OnDead() { CHECK_EQ(sync.size(), 0); } void ThreadContext::OnJoined(void *arg) { ThreadState *caller_thr = static_cast(arg); AcquireImpl(caller_thr, 0, &sync); sync.Reset(&caller_thr->clock_cache); } struct OnCreatedArgs { ThreadState *thr; uptr pc; }; void ThreadContext::OnCreated(void *arg) { thr = 0; if (tid == 0) return; OnCreatedArgs *args = static_cast(arg); args->thr->fast_state.IncrementEpoch(); // Can't increment epoch w/o writing to the trace as well. TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0); ReleaseImpl(args->thr, 0, &sync); creation_stack_id = CurrentStackId(args->thr, args->pc); if (reuse_count == 0) StatInc(args->thr, StatThreadMaxTid); } void ThreadContext::OnReset() { CHECK_EQ(sync.size(), 0); FlushUnneededShadowMemory(GetThreadTrace(tid), TraceSize() * sizeof(Event)); //!!! FlushUnneededShadowMemory(GetThreadTraceHeader(tid), sizeof(Trace)); } void ThreadContext::OnDetached(void *arg) { ThreadState *thr1 = static_cast(arg); sync.Reset(&thr1->clock_cache); } struct OnStartedArgs { ThreadState *thr; uptr stk_addr; uptr stk_size; uptr tls_addr; uptr tls_size; }; void ThreadContext::OnStarted(void *arg) { OnStartedArgs *args = static_cast(arg); thr = args->thr; // RoundUp so that one trace part does not contain events // from different threads. epoch0 = RoundUp(epoch1 + 1, kTracePartSize); epoch1 = (u64)-1; new(thr) ThreadState(ctx, tid, unique_id, epoch0, reuse_count, args->stk_addr, args->stk_size, args->tls_addr, args->tls_size); #ifndef SANITIZER_GO thr->shadow_stack = &ThreadTrace(thr->tid)->shadow_stack[0]; thr->shadow_stack_pos = thr->shadow_stack; thr->shadow_stack_end = thr->shadow_stack + kShadowStackSize; #else // Setup dynamic shadow stack. const int kInitStackSize = 8; thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack, kInitStackSize * sizeof(uptr)); thr->shadow_stack_pos = thr->shadow_stack; thr->shadow_stack_end = thr->shadow_stack + kInitStackSize; #endif #ifndef SANITIZER_GO AllocatorThreadStart(thr); #endif if (common_flags()->detect_deadlocks) { thr->dd_pt = ctx->dd->CreatePhysicalThread(); thr->dd_lt = ctx->dd->CreateLogicalThread(unique_id); } thr->fast_state.SetHistorySize(flags()->history_size); // Commit switch to the new part of the trace. // TraceAddEvent will reset stack0/mset0 in the new part for us. TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); thr->fast_synch_epoch = epoch0; AcquireImpl(thr, 0, &sync); StatInc(thr, StatSyncAcquire); sync.Reset(&thr->clock_cache); DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx " "tls_addr=%zx tls_size=%zx\n", tid, (uptr)epoch0, args->stk_addr, args->stk_size, args->tls_addr, args->tls_size); } void ThreadContext::OnFinished() { if (!detached) { thr->fast_state.IncrementEpoch(); // Can't increment epoch w/o writing to the trace as well. TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); ReleaseImpl(thr, 0, &sync); } epoch1 = thr->fast_state.epoch(); if (common_flags()->detect_deadlocks) { ctx->dd->DestroyPhysicalThread(thr->dd_pt); ctx->dd->DestroyLogicalThread(thr->dd_lt); } ctx->clock_alloc.FlushCache(&thr->clock_cache); ctx->metamap.OnThreadIdle(thr); #ifndef SANITIZER_GO AllocatorThreadFinish(thr); #endif thr->~ThreadState(); +#if TSAN_COLLECT_STATS StatAggregate(ctx->stat, thr->stat); +#endif thr = 0; } #ifndef SANITIZER_GO struct ThreadLeak { ThreadContext *tctx; int count; }; static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) { Vector &leaks = *(Vector*)arg; ThreadContext *tctx = static_cast(tctx_base); if (tctx->detached || tctx->status != ThreadStatusFinished) return; for (uptr i = 0; i < leaks.Size(); i++) { if (leaks[i].tctx->creation_stack_id == tctx->creation_stack_id) { leaks[i].count++; return; } } ThreadLeak leak = {tctx, 1}; leaks.PushBack(leak); } #endif #ifndef SANITIZER_GO static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) { if (tctx->tid == 0) { Printf("ThreadSanitizer: main thread finished with ignores enabled\n"); } else { Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled," " created at:\n", tctx->tid, tctx->name); PrintStack(SymbolizeStackId(tctx->creation_stack_id)); } Printf(" One of the following ignores was not ended" " (in order of probability)\n"); for (uptr i = 0; i < set->Size(); i++) { Printf(" Ignore was enabled at:\n"); PrintStack(SymbolizeStackId(set->At(i))); } Die(); } static void ThreadCheckIgnore(ThreadState *thr) { if (ctx->after_multithreaded_fork) return; if (thr->ignore_reads_and_writes) ReportIgnoresEnabled(thr->tctx, &thr->mop_ignore_set); if (thr->ignore_sync) ReportIgnoresEnabled(thr->tctx, &thr->sync_ignore_set); } #else static void ThreadCheckIgnore(ThreadState *thr) {} #endif void ThreadFinalize(ThreadState *thr) { ThreadCheckIgnore(thr); #ifndef SANITIZER_GO if (!flags()->report_thread_leaks) return; ThreadRegistryLock l(ctx->thread_registry); Vector leaks(MBlockScopedBuf); ctx->thread_registry->RunCallbackForEachThreadLocked( MaybeReportThreadLeak, &leaks); for (uptr i = 0; i < leaks.Size(); i++) { ScopedReport rep(ReportTypeThreadLeak); rep.AddThread(leaks[i].tctx, true); rep.SetCount(leaks[i].count); OutputReport(thr, rep); } #endif } int ThreadCount(ThreadState *thr) { uptr result; ctx->thread_registry->GetNumberOfThreads(0, 0, &result); return (int)result; } int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) { StatInc(thr, StatThreadCreate); OnCreatedArgs args = { thr, pc }; int tid = ctx->thread_registry->CreateThread(uid, detached, thr->tid, &args); DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", thr->tid, tid, uid); StatSet(thr, StatThreadMaxAlive, ctx->thread_registry->GetMaxAliveThreads()); return tid; } void ThreadStart(ThreadState *thr, int tid, uptr os_id) { uptr stk_addr = 0; uptr stk_size = 0; uptr tls_addr = 0; uptr tls_size = 0; +#ifndef SANITIZER_GO GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size); if (tid) { if (stk_addr && stk_size) MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size); if (tls_addr && tls_size) { // Check that the thr object is in tls; const uptr thr_beg = (uptr)thr; const uptr thr_end = (uptr)thr + sizeof(*thr); CHECK_GE(thr_beg, tls_addr); CHECK_LE(thr_beg, tls_addr + tls_size); CHECK_GE(thr_end, tls_addr); CHECK_LE(thr_end, tls_addr + tls_size); // Since the thr object is huge, skip it. MemoryRangeImitateWrite(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr); MemoryRangeImitateWrite(thr, /*pc=*/ 2, thr_end, tls_addr + tls_size - thr_end); } } +#endif ThreadRegistry *tr = ctx->thread_registry; OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size }; tr->StartThread(tid, os_id, &args); tr->Lock(); thr->tctx = (ThreadContext*)tr->GetThreadLocked(tid); tr->Unlock(); #ifndef SANITIZER_GO if (ctx->after_multithreaded_fork) { thr->ignore_interceptors++; ThreadIgnoreBegin(thr, 0); ThreadIgnoreSyncBegin(thr, 0); } #endif } void ThreadFinish(ThreadState *thr) { ThreadCheckIgnore(thr); StatInc(thr, StatThreadFinish); if (thr->stk_addr && thr->stk_size) DontNeedShadowFor(thr->stk_addr, thr->stk_size); if (thr->tls_addr && thr->tls_size) DontNeedShadowFor(thr->tls_addr, thr->tls_size); thr->is_dead = true; ctx->thread_registry->FinishThread(thr->tid); } static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) { uptr uid = (uptr)arg; if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) { tctx->user_id = 0; return true; } return false; } int ThreadTid(ThreadState *thr, uptr pc, uptr uid) { int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid); DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res); return res; } void ThreadJoin(ThreadState *thr, uptr pc, int tid) { CHECK_GT(tid, 0); CHECK_LT(tid, kMaxTid); DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid); ctx->thread_registry->JoinThread(tid, thr); } void ThreadDetach(ThreadState *thr, uptr pc, int tid) { CHECK_GT(tid, 0); CHECK_LT(tid, kMaxTid); ctx->thread_registry->DetachThread(tid, thr); } void ThreadSetName(ThreadState *thr, const char *name) { ctx->thread_registry->SetThreadName(thr->tid, name); } void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, uptr size, bool is_write) { if (size == 0) return; u64 *shadow_mem = (u64*)MemToShadow(addr); DPrintf2("#%d: MemoryAccessRange: @%p %p size=%d is_write=%d\n", thr->tid, (void*)pc, (void*)addr, (int)size, is_write); #if SANITIZER_DEBUG if (!IsAppMem(addr)) { Printf("Access to non app mem %zx\n", addr); DCHECK(IsAppMem(addr)); } if (!IsAppMem(addr + size - 1)) { Printf("Access to non app mem %zx\n", addr + size - 1); DCHECK(IsAppMem(addr + size - 1)); } if (!IsShadowMem((uptr)shadow_mem)) { Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr); DCHECK(IsShadowMem((uptr)shadow_mem)); } if (!IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1))) { Printf("Bad shadow addr %p (%zx)\n", shadow_mem + size * kShadowCnt / 8 - 1, addr + size - 1); DCHECK(IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1))); } #endif StatInc(thr, StatMopRange); if (*shadow_mem == kShadowRodata) { // Access to .rodata section, no races here. // Measurements show that it can be 10-20% of all memory accesses. StatInc(thr, StatMopRangeRodata); return; } FastState fast_state = thr->fast_state; if (fast_state.GetIgnoreBit()) return; fast_state.IncrementEpoch(); thr->fast_state = fast_state; TraceAddEvent(thr, fast_state, EventTypeMop, pc); bool unaligned = (addr % kShadowCell) != 0; // Handle unaligned beginning, if any. for (; addr % kShadowCell && size; addr++, size--) { int const kAccessSizeLog = 0; Shadow cur(fast_state); cur.SetWrite(is_write); cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog); MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false, shadow_mem, cur); } if (unaligned) shadow_mem += kShadowCnt; // Handle middle part, if any. for (; size >= kShadowCell; addr += kShadowCell, size -= kShadowCell) { int const kAccessSizeLog = 3; Shadow cur(fast_state); cur.SetWrite(is_write); cur.SetAddr0AndSizeLog(0, kAccessSizeLog); MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false, shadow_mem, cur); shadow_mem += kShadowCnt; } // Handle ending, if any. for (; size; addr++, size--) { int const kAccessSizeLog = 0; Shadow cur(fast_state); cur.SetWrite(is_write); cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog); MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false, shadow_mem, cur); } } } // namespace __tsan Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_stat.cc (revision 279194) @@ -1,179 +1,178 @@ //===-- tsan_stat.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 ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// #include "tsan_stat.h" #include "tsan_rtl.h" namespace __tsan { +#if TSAN_COLLECT_STATS + void StatAggregate(u64 *dst, u64 *src) { - if (!kCollectStats) - return; for (int i = 0; i < StatCnt; i++) dst[i] += src[i]; } void StatOutput(u64 *stat) { - if (!kCollectStats) - return; - stat[StatShadowNonZero] = stat[StatShadowProcessed] - stat[StatShadowZero]; static const char *name[StatCnt] = {}; name[StatMop] = "Memory accesses "; name[StatMopRead] = " Including reads "; name[StatMopWrite] = " writes "; name[StatMop1] = " Including size 1 "; name[StatMop2] = " size 2 "; name[StatMop4] = " size 4 "; name[StatMop8] = " size 8 "; name[StatMopSame] = " Including same "; name[StatMopIgnored] = " Including ignored "; name[StatMopRange] = " Including range "; name[StatMopRodata] = " Including .rodata "; name[StatMopRangeRodata] = " Including .rodata range "; name[StatShadowProcessed] = "Shadow processed "; name[StatShadowZero] = " Including empty "; name[StatShadowNonZero] = " Including non empty "; name[StatShadowSameSize] = " Including same size "; name[StatShadowIntersect] = " intersect "; name[StatShadowNotIntersect] = " not intersect "; name[StatShadowSameThread] = " Including same thread "; name[StatShadowAnotherThread] = " another thread "; name[StatShadowReplace] = " Including evicted "; name[StatFuncEnter] = "Function entries "; name[StatFuncExit] = "Function exits "; name[StatEvents] = "Events collected "; name[StatThreadCreate] = "Total threads created "; name[StatThreadFinish] = " threads finished "; name[StatThreadReuse] = " threads reused "; name[StatThreadMaxTid] = " max tid "; name[StatThreadMaxAlive] = " max alive threads "; name[StatMutexCreate] = "Mutexes created "; name[StatMutexDestroy] = " destroyed "; name[StatMutexLock] = " lock "; name[StatMutexUnlock] = " unlock "; name[StatMutexRecLock] = " recursive lock "; name[StatMutexRecUnlock] = " recursive unlock "; name[StatMutexReadLock] = " read lock "; name[StatMutexReadUnlock] = " read unlock "; name[StatSyncCreated] = "Sync objects created "; name[StatSyncDestroyed] = " destroyed "; name[StatSyncAcquire] = " acquired "; name[StatSyncRelease] = " released "; name[StatClockAcquire] = "Clock acquire "; name[StatClockAcquireEmpty] = " empty clock "; name[StatClockAcquireFastRelease] = " fast from release-store "; name[StatClockAcquireLarge] = " contains my tid "; name[StatClockAcquireRepeat] = " repeated (fast) "; name[StatClockAcquireFull] = " full (slow) "; name[StatClockAcquiredSomething] = " acquired something "; name[StatClockRelease] = "Clock release "; name[StatClockReleaseResize] = " resize "; name[StatClockReleaseFast1] = " fast1 "; name[StatClockReleaseFast2] = " fast2 "; name[StatClockReleaseSlow] = " dirty overflow (slow) "; name[StatClockReleaseFull] = " full (slow) "; name[StatClockReleaseAcquired] = " was acquired "; name[StatClockReleaseClearTail] = " clear tail "; name[StatClockStore] = "Clock release store "; name[StatClockStoreResize] = " resize "; name[StatClockStoreFast] = " fast "; name[StatClockStoreFull] = " slow "; name[StatClockStoreTail] = " clear tail "; name[StatClockAcquireRelease] = "Clock acquire-release "; name[StatAtomic] = "Atomic operations "; name[StatAtomicLoad] = " Including load "; name[StatAtomicStore] = " store "; name[StatAtomicExchange] = " exchange "; name[StatAtomicFetchAdd] = " fetch_add "; name[StatAtomicFetchSub] = " fetch_sub "; name[StatAtomicFetchAnd] = " fetch_and "; name[StatAtomicFetchOr] = " fetch_or "; name[StatAtomicFetchXor] = " fetch_xor "; name[StatAtomicFetchNand] = " fetch_nand "; name[StatAtomicCAS] = " compare_exchange "; name[StatAtomicFence] = " fence "; name[StatAtomicRelaxed] = " Including relaxed "; name[StatAtomicConsume] = " consume "; name[StatAtomicAcquire] = " acquire "; name[StatAtomicRelease] = " release "; name[StatAtomicAcq_Rel] = " acq_rel "; name[StatAtomicSeq_Cst] = " seq_cst "; name[StatAtomic1] = " Including size 1 "; name[StatAtomic2] = " size 2 "; name[StatAtomic4] = " size 4 "; name[StatAtomic8] = " size 8 "; name[StatAtomic16] = " size 16 "; name[StatAnnotation] = "Dynamic annotations "; name[StatAnnotateHappensBefore] = " HappensBefore "; name[StatAnnotateHappensAfter] = " HappensAfter "; name[StatAnnotateCondVarSignal] = " CondVarSignal "; name[StatAnnotateCondVarSignalAll] = " CondVarSignalAll "; name[StatAnnotateMutexIsNotPHB] = " MutexIsNotPHB "; name[StatAnnotateCondVarWait] = " CondVarWait "; name[StatAnnotateRWLockCreate] = " RWLockCreate "; name[StatAnnotateRWLockCreateStatic] = " StatAnnotateRWLockCreateStatic "; name[StatAnnotateRWLockDestroy] = " RWLockDestroy "; name[StatAnnotateRWLockAcquired] = " RWLockAcquired "; name[StatAnnotateRWLockReleased] = " RWLockReleased "; name[StatAnnotateTraceMemory] = " TraceMemory "; name[StatAnnotateFlushState] = " FlushState "; name[StatAnnotateNewMemory] = " NewMemory "; name[StatAnnotateNoOp] = " NoOp "; name[StatAnnotateFlushExpectedRaces] = " FlushExpectedRaces "; name[StatAnnotateEnableRaceDetection] = " EnableRaceDetection "; name[StatAnnotateMutexIsUsedAsCondVar] = " MutexIsUsedAsCondVar "; name[StatAnnotatePCQGet] = " PCQGet "; name[StatAnnotatePCQPut] = " PCQPut "; name[StatAnnotatePCQDestroy] = " PCQDestroy "; name[StatAnnotatePCQCreate] = " PCQCreate "; name[StatAnnotateExpectRace] = " ExpectRace "; name[StatAnnotateBenignRaceSized] = " BenignRaceSized "; name[StatAnnotateBenignRace] = " BenignRace "; name[StatAnnotateIgnoreReadsBegin] = " IgnoreReadsBegin "; name[StatAnnotateIgnoreReadsEnd] = " IgnoreReadsEnd "; name[StatAnnotateIgnoreWritesBegin] = " IgnoreWritesBegin "; name[StatAnnotateIgnoreWritesEnd] = " IgnoreWritesEnd "; name[StatAnnotateIgnoreSyncBegin] = " IgnoreSyncBegin "; name[StatAnnotateIgnoreSyncEnd] = " IgnoreSyncEnd "; name[StatAnnotatePublishMemoryRange] = " PublishMemoryRange "; name[StatAnnotateUnpublishMemoryRange] = " UnpublishMemoryRange "; name[StatAnnotateThreadName] = " ThreadName "; name[StatMtxTotal] = "Contentionz "; name[StatMtxTrace] = " Trace "; name[StatMtxThreads] = " Threads "; name[StatMtxReport] = " Report "; name[StatMtxSyncVar] = " SyncVar "; name[StatMtxSyncTab] = " SyncTab "; name[StatMtxSlab] = " Slab "; name[StatMtxAtExit] = " Atexit "; name[StatMtxAnnotations] = " Annotations "; name[StatMtxMBlock] = " MBlock "; name[StatMtxJavaMBlock] = " JavaMBlock "; name[StatMtxDeadlockDetector] = " DeadlockDetector "; name[StatMtxFD] = " FD "; Printf("Statistics:\n"); for (int i = 0; i < StatCnt; i++) Printf("%s: %16zu\n", name[i], (uptr)stat[i]); } + +#endif } // namespace __tsan Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.cc (revision 279194) @@ -1,144 +1,157 @@ //===-- tsan_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 ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_suppressions.h" #include "tsan_suppressions.h" #include "tsan_rtl.h" #include "tsan_flags.h" #include "tsan_mman.h" #include "tsan_platform.h" // Suppressions for true/false positives in standard libraries. static const char *const std_suppressions = // Libstdc++ 4.4 has data races in std::string. // See http://crbug.com/181502 for an example. "race:^_M_rep$\n" "race:^_M_is_leaked$\n" // False positive when using std . // Happens because we miss atomic synchronization in libstdc++. // See http://llvm.org/bugs/show_bug.cgi?id=17066 for details. "race:std::_Sp_counted_ptr_inplaceParseFromFile(flags()->suppressions); #ifndef SANITIZER_GO - SuppressionContext::Get()->Parse(__tsan_default_suppressions()); - SuppressionContext::Get()->Parse(std_suppressions); + suppression_ctx->Parse(__tsan_default_suppressions()); + suppression_ctx->Parse(std_suppressions); #endif - suppressions_inited = true; } -SuppressionType conv(ReportType typ) { +SuppressionContext *Suppressions() { + CHECK(suppression_ctx); + return suppression_ctx; +} + +static const char *conv(ReportType typ) { if (typ == ReportTypeRace) - return SuppressionRace; + return kSuppressionRace; else if (typ == ReportTypeVptrRace) - return SuppressionRace; + return kSuppressionRace; else if (typ == ReportTypeUseAfterFree) - return SuppressionRace; + return kSuppressionRace; else if (typ == ReportTypeVptrUseAfterFree) - return SuppressionRace; + return kSuppressionRace; else if (typ == ReportTypeThreadLeak) - return SuppressionThread; + return kSuppressionThread; else if (typ == ReportTypeMutexDestroyLocked) - return SuppressionMutex; + return kSuppressionMutex; else if (typ == ReportTypeMutexDoubleLock) - return SuppressionMutex; + return kSuppressionMutex; else if (typ == ReportTypeMutexBadUnlock) - return SuppressionMutex; + return kSuppressionMutex; else if (typ == ReportTypeMutexBadReadLock) - return SuppressionMutex; + return kSuppressionMutex; else if (typ == ReportTypeMutexBadReadUnlock) - return SuppressionMutex; + return kSuppressionMutex; else if (typ == ReportTypeSignalUnsafe) - return SuppressionSignal; + return kSuppressionSignal; else if (typ == ReportTypeErrnoInSignal) - return SuppressionNone; + return kSuppressionNone; else if (typ == ReportTypeDeadlock) - return SuppressionDeadlock; + return kSuppressionDeadlock; Printf("ThreadSanitizer: unknown report type %d\n", typ), Die(); } uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) { - if (!SuppressionContext::Get()->SuppressionCount() || stack == 0 || + CHECK(suppression_ctx); + if (!suppression_ctx->SuppressionCount() || stack == 0 || !stack->suppressable) return 0; - SuppressionType stype = conv(typ); - if (stype == SuppressionNone) + const char *stype = conv(typ); + if (0 == internal_strcmp(stype, kSuppressionNone)) return 0; Suppression *s; for (const SymbolizedStack *frame = stack->frames; frame; frame = frame->next) { const AddressInfo &info = frame->info; - if (SuppressionContext::Get()->Match(info.function, stype, &s) || - SuppressionContext::Get()->Match(info.file, stype, &s) || - SuppressionContext::Get()->Match(info.module, stype, &s)) { + if (suppression_ctx->Match(info.function, stype, &s) || + suppression_ctx->Match(info.file, stype, &s) || + suppression_ctx->Match(info.module, stype, &s)) { DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ); s->hit_count++; *sp = s; return info.address; } } return 0; } uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) { - if (!SuppressionContext::Get()->SuppressionCount() || loc == 0 || + CHECK(suppression_ctx); + if (!suppression_ctx->SuppressionCount() || loc == 0 || loc->type != ReportLocationGlobal || !loc->suppressable) return 0; - SuppressionType stype = conv(typ); - if (stype == SuppressionNone) + const char *stype = conv(typ); + if (0 == internal_strcmp(stype, kSuppressionNone)) return 0; Suppression *s; const DataInfo &global = loc->global; - if (SuppressionContext::Get()->Match(global.name, stype, &s) || - SuppressionContext::Get()->Match(global.module, stype, &s)) { + if (suppression_ctx->Match(global.name, stype, &s) || + suppression_ctx->Match(global.module, stype, &s)) { DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ); s->hit_count++; *sp = s; return global.start; } return 0; } void PrintMatchedSuppressions() { InternalMmapVector matched(1); - SuppressionContext::Get()->GetMatched(&matched); + CHECK(suppression_ctx); + suppression_ctx->GetMatched(&matched); if (!matched.size()) return; int hit_count = 0; for (uptr i = 0; i < matched.size(); i++) hit_count += matched[i]->hit_count; Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count, (int)internal_getpid()); for (uptr i = 0; i < matched.size(); i++) { - Printf("%d %s:%s\n", matched[i]->hit_count, - SuppressionTypeString(matched[i]->type), matched[i]->templ); + Printf("%d %s:%s\n", matched[i]->hit_count, matched[i]->type, + matched[i]->templ); } } } // namespace __tsan Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_suppressions.h (revision 279194) @@ -1,28 +1,37 @@ //===-- tsan_suppressions.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. // //===----------------------------------------------------------------------===// #ifndef TSAN_SUPPRESSIONS_H #define TSAN_SUPPRESSIONS_H #include "sanitizer_common/sanitizer_suppressions.h" #include "tsan_report.h" namespace __tsan { +const char kSuppressionNone[] = "none"; +const char kSuppressionRace[] = "race"; +const char kSuppressionMutex[] = "mutex"; +const char kSuppressionThread[] = "thread"; +const char kSuppressionSignal[] = "signal"; +const char kSuppressionLib[] = "called_from_lib"; +const char kSuppressionDeadlock[] = "deadlock"; + void InitializeSuppressions(); +SuppressionContext *Suppressions(); void PrintMatchedSuppressions(); uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp); uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp); } // namespace __tsan #endif // TSAN_SUPPRESSIONS_H Index: projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_trace.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_trace.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/tsan/rtl/tsan_trace.h (revision 279194) @@ -1,72 +1,74 @@ //===-- tsan_trace.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. // //===----------------------------------------------------------------------===// #ifndef TSAN_TRACE_H #define TSAN_TRACE_H #include "tsan_defs.h" #include "tsan_mutex.h" #include "tsan_stack_trace.h" #include "tsan_mutexset.h" namespace __tsan { -const int kTracePartSizeBits = 14; +const int kTracePartSizeBits = 13; const int kTracePartSize = 1 << kTracePartSizeBits; -const int kTraceParts = 4 * 1024 * 1024 / kTracePartSize; +const int kTraceParts = 2 * 1024 * 1024 / kTracePartSize; const int kTraceSize = kTracePartSize * kTraceParts; // Must fit into 3 bits. enum EventType { EventTypeMop, EventTypeFuncEnter, EventTypeFuncExit, EventTypeLock, EventTypeUnlock, EventTypeRLock, EventTypeRUnlock }; // Represents a thread event (from most significant bit): // u64 typ : 3; // EventType. // u64 addr : 61; // Associated pc. typedef u64 Event; struct TraceHeader { #ifndef SANITIZER_GO BufferedStackTrace stack0; // Start stack for the trace. #else VarSizeStackTrace stack0; #endif u64 epoch0; // Start epoch for the trace. MutexSet mset0; TraceHeader() : stack0(), epoch0() {} }; struct Trace { - TraceHeader headers[kTraceParts]; Mutex mtx; #ifndef SANITIZER_GO // Must be last to catch overflow as paging fault. // Go shadow stack is dynamically allocated. uptr shadow_stack[kShadowStackSize]; #endif + // Must be the last field, because we unmap the unused part in + // CreateThreadContext. + TraceHeader headers[kTraceParts]; Trace() : mtx(MutexTypeTrace, StatMtxTrace) { } }; } // namespace __tsan #endif // TSAN_TRACE_H Index: projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_diag.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_diag.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_diag.cc (revision 279194) @@ -1,366 +1,358 @@ //===-- ubsan_diag.cc -----------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Diagnostic reporting for the UBSan runtime. // //===----------------------------------------------------------------------===// #include "ubsan_diag.h" #include "ubsan_init.h" #include "ubsan_flags.h" +#include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_report_decorator.h" #include "sanitizer_common/sanitizer_stacktrace.h" #include "sanitizer_common/sanitizer_stacktrace_printer.h" +#include "sanitizer_common/sanitizer_suppressions.h" #include "sanitizer_common/sanitizer_symbolizer.h" #include using namespace __ubsan; static void MaybePrintStackTrace(uptr pc, uptr bp) { // We assume that flags are already parsed: InitIfNecessary // will definitely be called when we print the first diagnostics message. if (!flags()->print_stacktrace) return; // We can only use slow unwind, as we don't have any information about stack // top/bottom. // FIXME: It's better to respect "fast_unwind_on_fatal" runtime flag and // fetch stack top/bottom information if we have it (e.g. if we're running // under ASan). if (StackTrace::WillUseFastUnwind(false)) return; BufferedStackTrace stack; stack.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, false); stack.Print(); } static void MaybeReportErrorSummary(Location Loc) { if (!common_flags()->print_summary) return; // Don't try to unwind the stack trace in UBSan summaries: just use the // provided location. if (Loc.isSourceLocation()) { SourceLocation SLoc = Loc.getSourceLocation(); if (!SLoc.isInvalid()) { ReportErrorSummary("undefined-behavior", SLoc.getFilename(), SLoc.getLine(), ""); return; } } ReportErrorSummary("undefined-behavior"); } namespace { class Decorator : public SanitizerCommonDecorator { public: Decorator() : SanitizerCommonDecorator() {} const char *Highlight() const { return Green(); } const char *EndHighlight() const { return Default(); } const char *Note() const { return Black(); } const char *EndNote() const { return Default(); } }; } -Location __ubsan::getCallerLocation(uptr CallerLoc) { - if (!CallerLoc) - return Location(); - - uptr Loc = StackTrace::GetPreviousInstructionPc(CallerLoc); - return getFunctionLocation(Loc, 0); -} - -Location __ubsan::getFunctionLocation(uptr Loc, const char **FName) { - if (!Loc) - return Location(); +SymbolizedStack *__ubsan::getSymbolizedLocation(uptr PC) { InitIfNecessary(); - - SymbolizedStack *Frames = Symbolizer::GetOrInit()->SymbolizePC(Loc); - const AddressInfo &Info = Frames->info; - - if (!Info.module) { - Frames->ClearAll(); - return Location(Loc); - } - - if (FName && Info.function) - *FName = internal_strdup(Info.function); - - if (!Info.file) { - ModuleLocation MLoc(internal_strdup(Info.module), Info.module_offset); - Frames->ClearAll(); - return MLoc; - } - - SourceLocation SLoc(internal_strdup(Info.file), Info.line, Info.column); - Frames->ClearAll(); - return SLoc; + return Symbolizer::GetOrInit()->SymbolizePC(PC); } Diag &Diag::operator<<(const TypeDescriptor &V) { return AddArg(V.getTypeName()); } Diag &Diag::operator<<(const Value &V) { if (V.getType().isSignedIntegerTy()) AddArg(V.getSIntValue()); else if (V.getType().isUnsignedIntegerTy()) AddArg(V.getUIntValue()); else if (V.getType().isFloatTy()) AddArg(V.getFloatValue()); else AddArg(""); return *this; } /// Hexadecimal printing for numbers too large for Printf to handle directly. static void PrintHex(UIntMax Val) { #if HAVE_INT128_T Printf("0x%08x%08x%08x%08x", (unsigned int)(Val >> 96), (unsigned int)(Val >> 64), (unsigned int)(Val >> 32), (unsigned int)(Val)); #else UNREACHABLE("long long smaller than 64 bits?"); #endif } static void renderLocation(Location Loc) { InternalScopedString LocBuffer(1024); switch (Loc.getKind()) { case Location::LK_Source: { SourceLocation SLoc = Loc.getSourceLocation(); if (SLoc.isInvalid()) LocBuffer.append(""); else RenderSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(), SLoc.getColumn(), common_flags()->strip_path_prefix); break; } - case Location::LK_Module: { - ModuleLocation MLoc = Loc.getModuleLocation(); - RenderModuleLocation(&LocBuffer, MLoc.getModuleName(), MLoc.getOffset(), - common_flags()->strip_path_prefix); - break; - } case Location::LK_Memory: LocBuffer.append("%p", Loc.getMemoryLocation()); break; + case Location::LK_Symbolized: { + const AddressInfo &Info = Loc.getSymbolizedStack()->info; + if (Info.file) { + RenderSourceLocation(&LocBuffer, Info.file, Info.line, Info.column, + common_flags()->strip_path_prefix); + } else if (Info.module) { + RenderModuleLocation(&LocBuffer, Info.module, Info.module_offset, + common_flags()->strip_path_prefix); + } else { + LocBuffer.append("%p", Info.address); + } + break; + } case Location::LK_Null: LocBuffer.append(""); break; } Printf("%s:", LocBuffer.data()); } static void renderText(const char *Message, const Diag::Arg *Args) { for (const char *Msg = Message; *Msg; ++Msg) { if (*Msg != '%') { char Buffer[64]; unsigned I; for (I = 0; Msg[I] && Msg[I] != '%' && I != 63; ++I) Buffer[I] = Msg[I]; Buffer[I] = '\0'; Printf(Buffer); Msg += I - 1; } else { const Diag::Arg &A = Args[*++Msg - '0']; switch (A.Kind) { case Diag::AK_String: Printf("%s", A.String); break; case Diag::AK_Mangled: { Printf("'%s'", Symbolizer::GetOrInit()->Demangle(A.String)); break; } case Diag::AK_SInt: // 'long long' is guaranteed to be at least 64 bits wide. if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX) Printf("%lld", (long long)A.SInt); else PrintHex(A.SInt); break; case Diag::AK_UInt: if (A.UInt <= UINT64_MAX) Printf("%llu", (unsigned long long)A.UInt); else PrintHex(A.UInt); break; case Diag::AK_Float: { // FIXME: Support floating-point formatting in sanitizer_common's // printf, and stop using snprintf here. char Buffer[32]; snprintf(Buffer, sizeof(Buffer), "%Lg", (long double)A.Float); Printf("%s", Buffer); break; } case Diag::AK_Pointer: Printf("%p", A.Pointer); break; } } } } /// Find the earliest-starting range in Ranges which ends after Loc. static Range *upperBound(MemoryLocation Loc, Range *Ranges, unsigned NumRanges) { Range *Best = 0; for (unsigned I = 0; I != NumRanges; ++I) if (Ranges[I].getEnd().getMemoryLocation() > Loc && (!Best || Best->getStart().getMemoryLocation() > Ranges[I].getStart().getMemoryLocation())) Best = &Ranges[I]; return Best; } static inline uptr subtractNoOverflow(uptr LHS, uptr RHS) { return (LHS < RHS) ? 0 : LHS - RHS; } static inline uptr addNoOverflow(uptr LHS, uptr RHS) { const uptr Limit = (uptr)-1; return (LHS > Limit - RHS) ? Limit : LHS + RHS; } /// Render a snippet of the address space near a location. static void renderMemorySnippet(const Decorator &Decor, MemoryLocation Loc, Range *Ranges, unsigned NumRanges, const Diag::Arg *Args) { // Show at least the 8 bytes surrounding Loc. const unsigned MinBytesNearLoc = 4; MemoryLocation Min = subtractNoOverflow(Loc, MinBytesNearLoc); MemoryLocation Max = addNoOverflow(Loc, MinBytesNearLoc); MemoryLocation OrigMin = Min; for (unsigned I = 0; I < NumRanges; ++I) { Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min); Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max); } // If we have too many interesting bytes, prefer to show bytes after Loc. const unsigned BytesToShow = 32; if (Max - Min > BytesToShow) Min = __sanitizer::Min(Max - BytesToShow, OrigMin); Max = addNoOverflow(Min, BytesToShow); if (!IsAccessibleMemoryRange(Min, Max - Min)) { Printf("\n"); return; } // Emit data. for (uptr P = Min; P != Max; ++P) { unsigned char C = *reinterpret_cast(P); Printf("%s%02x", (P % 8 == 0) ? " " : " ", C); } Printf("\n"); // Emit highlights. Printf(Decor.Highlight()); Range *InRange = upperBound(Min, Ranges, NumRanges); for (uptr P = Min; P != Max; ++P) { char Pad = ' ', Byte = ' '; if (InRange && InRange->getEnd().getMemoryLocation() == P) InRange = upperBound(P, Ranges, NumRanges); if (!InRange && P > Loc) break; if (InRange && InRange->getStart().getMemoryLocation() < P) Pad = '~'; if (InRange && InRange->getStart().getMemoryLocation() <= P) Byte = '~'; char Buffer[] = { Pad, Pad, P == Loc ? '^' : Byte, Byte, 0 }; Printf((P % 8 == 0) ? Buffer : &Buffer[1]); } Printf("%s\n", Decor.EndHighlight()); // Go over the line again, and print names for the ranges. InRange = 0; unsigned Spaces = 0; for (uptr P = Min; P != Max; ++P) { if (!InRange || InRange->getEnd().getMemoryLocation() == P) InRange = upperBound(P, Ranges, NumRanges); if (!InRange) break; Spaces += (P % 8) == 0 ? 2 : 1; if (InRange && InRange->getStart().getMemoryLocation() == P) { while (Spaces--) Printf(" "); renderText(InRange->getText(), Args); Printf("\n"); // FIXME: We only support naming one range for now! break; } Spaces += 2; } // FIXME: Print names for anything we can identify within the line: // // * If we can identify the memory itself as belonging to a particular // global, stack variable, or dynamic allocation, then do so. // // * If we have a pointer-size, pointer-aligned range highlighted, // determine whether the value of that range is a pointer to an // entity which we can name, and if so, print that name. // // This needs an external symbolizer, or (preferably) ASan instrumentation. } Diag::~Diag() { // All diagnostics should be printed under report mutex. CommonSanitizerReportMutex.CheckLocked(); Decorator Decor; Printf(Decor.Bold()); renderLocation(Loc); switch (Level) { case DL_Error: Printf("%s runtime error: %s%s", Decor.Warning(), Decor.EndWarning(), Decor.Bold()); break; case DL_Note: Printf("%s note: %s", Decor.Note(), Decor.EndNote()); break; } renderText(Message, Args); Printf("%s\n", Decor.Default()); if (Loc.isMemoryLocation()) renderMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges, NumRanges, Args); } ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc) : Opts(Opts), SummaryLoc(SummaryLoc) { InitIfNecessary(); CommonSanitizerReportMutex.Lock(); } ScopedReport::~ScopedReport() { MaybePrintStackTrace(Opts.pc, Opts.bp); MaybeReportErrorSummary(SummaryLoc); CommonSanitizerReportMutex.Unlock(); if (Opts.DieAfterReport || flags()->halt_on_error) Die(); } -bool __ubsan::MatchSuppression(const char *Str, SuppressionType Type) { - Suppression *s; +ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)]; +static SuppressionContext *suppression_ctx = nullptr; +static const char kVptrCheck[] = "vptr_check"; +static const char *kSuppressionTypes[] = { kVptrCheck }; + +void __ubsan::InitializeSuppressions() { + CHECK_EQ(nullptr, suppression_ctx); + suppression_ctx = new (suppression_placeholder) // NOLINT + SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); + suppression_ctx->ParseFromFile(flags()->suppressions); +} + +bool __ubsan::IsVptrCheckSuppressed(const char *TypeName) { // If .preinit_array is not used, it is possible that the UBSan runtime is not // initialized. if (!SANITIZER_CAN_USE_PREINIT_ARRAY) InitIfNecessary(); - return SuppressionContext::Get()->Match(Str, Type, &s); + CHECK(suppression_ctx); + Suppression *s; + return suppression_ctx->Match(TypeName, kVptrCheck, &s); } Index: projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_diag.h =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_diag.h (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_diag.h (revision 279194) @@ -1,237 +1,243 @@ //===-- ubsan_diag.h --------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Diagnostics emission for Clang's undefined behavior sanitizer. // //===----------------------------------------------------------------------===// #ifndef UBSAN_DIAG_H #define UBSAN_DIAG_H #include "ubsan_value.h" #include "sanitizer_common/sanitizer_stacktrace.h" -#include "sanitizer_common/sanitizer_suppressions.h" +#include "sanitizer_common/sanitizer_symbolizer.h" namespace __ubsan { -/// \brief A location within a loaded module in the program. These are used when -/// the location can't be resolved to a SourceLocation. -class ModuleLocation { - const char *ModuleName; - uptr Offset; +class SymbolizedStackHolder { + SymbolizedStack *Stack; + void clear() { + if (Stack) + Stack->ClearAll(); + } + public: - ModuleLocation() : ModuleName(0), Offset(0) {} - ModuleLocation(const char *ModuleName, uptr Offset) - : ModuleName(ModuleName), Offset(Offset) {} - const char *getModuleName() const { return ModuleName; } - uptr getOffset() const { return Offset; } + explicit SymbolizedStackHolder(SymbolizedStack *Stack = nullptr) + : Stack(Stack) {} + ~SymbolizedStackHolder() { clear(); } + void reset(SymbolizedStack *S) { + if (Stack != S) + clear(); + Stack = S; + } + const SymbolizedStack *get() const { return Stack; } }; +SymbolizedStack *getSymbolizedLocation(uptr PC); + +inline SymbolizedStack *getCallerLocation(uptr CallerPC) { + CHECK(CallerPC); + uptr PC = StackTrace::GetPreviousInstructionPc(CallerPC); + return getSymbolizedLocation(PC); +} + /// A location of some data within the program's address space. typedef uptr MemoryLocation; /// \brief Location at which a diagnostic can be emitted. Either a -/// SourceLocation, a ModuleLocation, or a MemoryLocation. +/// SourceLocation, a MemoryLocation, or a SymbolizedStack. class Location { public: - enum LocationKind { LK_Null, LK_Source, LK_Module, LK_Memory }; + enum LocationKind { LK_Null, LK_Source, LK_Memory, LK_Symbolized }; private: LocationKind Kind; // FIXME: In C++11, wrap these in an anonymous union. SourceLocation SourceLoc; - ModuleLocation ModuleLoc; MemoryLocation MemoryLoc; + const SymbolizedStack *SymbolizedLoc; // Not owned. public: Location() : Kind(LK_Null) {} Location(SourceLocation Loc) : Kind(LK_Source), SourceLoc(Loc) {} - Location(ModuleLocation Loc) : - Kind(LK_Module), ModuleLoc(Loc) {} Location(MemoryLocation Loc) : Kind(LK_Memory), MemoryLoc(Loc) {} + // SymbolizedStackHolder must outlive Location object. + Location(const SymbolizedStackHolder &Stack) : + Kind(LK_Symbolized), SymbolizedLoc(Stack.get()) {} LocationKind getKind() const { return Kind; } bool isSourceLocation() const { return Kind == LK_Source; } - bool isModuleLocation() const { return Kind == LK_Module; } bool isMemoryLocation() const { return Kind == LK_Memory; } + bool isSymbolizedStack() const { return Kind == LK_Symbolized; } SourceLocation getSourceLocation() const { CHECK(isSourceLocation()); return SourceLoc; } - ModuleLocation getModuleLocation() const { - CHECK(isModuleLocation()); - return ModuleLoc; - } MemoryLocation getMemoryLocation() const { CHECK(isMemoryLocation()); return MemoryLoc; } + const SymbolizedStack *getSymbolizedStack() const { + CHECK(isSymbolizedStack()); + return SymbolizedLoc; + } }; -/// Try to obtain a location for the caller. This might fail, and produce either -/// an invalid location or a module location for the caller. -Location getCallerLocation(uptr CallerLoc = GET_CALLER_PC()); - -/// Try to obtain a location for the given function pointer. This might fail, -/// and produce either an invalid location or a module location for the caller. -/// If FName is non-null and the name of the function is known, set *FName to -/// the function name, otherwise *FName is unchanged. -Location getFunctionLocation(uptr Loc, const char **FName); - /// A diagnostic severity level. enum DiagLevel { DL_Error, ///< An error. DL_Note ///< A note, attached to a prior diagnostic. }; /// \brief Annotation for a range of locations in a diagnostic. class Range { Location Start, End; const char *Text; public: Range() : Start(), End(), Text() {} Range(MemoryLocation Start, MemoryLocation End, const char *Text) : Start(Start), End(End), Text(Text) {} Location getStart() const { return Start; } Location getEnd() const { return End; } const char *getText() const { return Text; } }; /// \brief A mangled C++ name. Really just a strong typedef for 'const char*'. class MangledName { const char *Name; public: MangledName(const char *Name) : Name(Name) {} const char *getName() const { return Name; } }; /// \brief Representation of an in-flight diagnostic. /// /// Temporary \c Diag instances are created by the handler routines to /// accumulate arguments for a diagnostic. The destructor emits the diagnostic /// message. class Diag { /// The location at which the problem occurred. Location Loc; /// The diagnostic level. DiagLevel Level; /// The message which will be emitted, with %0, %1, ... placeholders for /// arguments. const char *Message; public: /// Kinds of arguments, corresponding to members of \c Arg's union. enum ArgKind { AK_String, ///< A string argument, displayed as-is. AK_Mangled,///< A C++ mangled name, demangled before display. AK_UInt, ///< An unsigned integer argument. AK_SInt, ///< A signed integer argument. AK_Float, ///< A floating-point argument. AK_Pointer ///< A pointer argument, displayed in hexadecimal. }; /// An individual diagnostic message argument. struct Arg { Arg() {} Arg(const char *String) : Kind(AK_String), String(String) {} Arg(MangledName MN) : Kind(AK_Mangled), String(MN.getName()) {} Arg(UIntMax UInt) : Kind(AK_UInt), UInt(UInt) {} Arg(SIntMax SInt) : Kind(AK_SInt), SInt(SInt) {} Arg(FloatMax Float) : Kind(AK_Float), Float(Float) {} Arg(const void *Pointer) : Kind(AK_Pointer), Pointer(Pointer) {} ArgKind Kind; union { const char *String; UIntMax UInt; SIntMax SInt; FloatMax Float; const void *Pointer; }; }; private: static const unsigned MaxArgs = 5; static const unsigned MaxRanges = 1; /// The arguments which have been added to this diagnostic so far. Arg Args[MaxArgs]; unsigned NumArgs; /// The ranges which have been added to this diagnostic so far. Range Ranges[MaxRanges]; unsigned NumRanges; Diag &AddArg(Arg A) { CHECK(NumArgs != MaxArgs); Args[NumArgs++] = A; return *this; } Diag &AddRange(Range A) { CHECK(NumRanges != MaxRanges); Ranges[NumRanges++] = A; return *this; } /// \c Diag objects are not copyable. Diag(const Diag &); // NOT IMPLEMENTED Diag &operator=(const Diag &); public: Diag(Location Loc, DiagLevel Level, const char *Message) : Loc(Loc), Level(Level), Message(Message), NumArgs(0), NumRanges(0) {} ~Diag(); Diag &operator<<(const char *Str) { return AddArg(Str); } Diag &operator<<(MangledName MN) { return AddArg(MN); } Diag &operator<<(unsigned long long V) { return AddArg(UIntMax(V)); } Diag &operator<<(const void *V) { return AddArg(V); } Diag &operator<<(const TypeDescriptor &V); Diag &operator<<(const Value &V); Diag &operator<<(const Range &R) { return AddRange(R); } }; struct ReportOptions { /// If DieAfterReport is specified, UBSan will terminate the program after the /// report is printed. bool DieAfterReport; /// pc/bp are used to unwind the stack trace. uptr pc; uptr bp; }; #define GET_REPORT_OPTIONS(die_after_report) \ GET_CALLER_PC_BP; \ ReportOptions Opts = {die_after_report, pc, bp} /// \brief Instantiate this class before printing diagnostics in the error /// report. This class ensures that reports from different threads and from /// different sanitizers won't be mixed. class ScopedReport { ReportOptions Opts; Location SummaryLoc; public: ScopedReport(ReportOptions Opts, Location SummaryLoc); ~ScopedReport(); }; -bool MatchSuppression(const char *Str, SuppressionType Type); +void InitializeSuppressions(); +bool IsVptrCheckSuppressed(const char *TypeName); } // namespace __ubsan #endif // UBSAN_DIAG_H Index: projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_flags.inc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_flags.inc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_flags.inc (revision 279194) @@ -1,24 +1,25 @@ //===-- ubsan_flags.inc -----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // UBSan runtime flags. // //===----------------------------------------------------------------------===// #ifndef UBSAN_FLAG # error "Define UBSAN_FLAG prior to including this file!" #endif // UBSAN_FLAG(Type, Name, DefaultValue, Description) // See COMMON_FLAG in sanitizer_flags.inc for more details. UBSAN_FLAG(bool, halt_on_error, false, "Crash the program after printing the first error report") UBSAN_FLAG(bool, print_stacktrace, false, "Include full stacktrace into an error report") +UBSAN_FLAG(const char *, suppressions, "", "Suppressions file name.") Index: projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc (revision 279194) @@ -1,412 +1,421 @@ //===-- ubsan_handlers.cc -------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Error logging entry points for the UBSan runtime. // //===----------------------------------------------------------------------===// #include "ubsan_handlers.h" #include "ubsan_diag.h" #include "sanitizer_common/sanitizer_common.h" using namespace __sanitizer; using namespace __ubsan; static bool ignoreReport(SourceLocation SLoc, ReportOptions Opts) { // If source location is already acquired, we don't need to print an error // report for the second time. However, if we're in an unrecoverable handler, // it's possible that location was required by concurrently running thread. // In this case, we should continue the execution to ensure that any of // threads will grab the report mutex and print the report before // crashing the program. return SLoc.isDisabled() && !Opts.DieAfterReport; } namespace __ubsan { const char *TypeCheckKinds[] = { "load of", "store to", "reference binding to", "member access within", "member call on", "constructor call on", "downcast of", "downcast of", "upcast of", "cast to virtual base of"}; } static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, - Location FallbackLoc, ReportOptions Opts) { + ReportOptions Opts) { Location Loc = Data->Loc.acquire(); // Use the SourceLocation from Data to track deduplication, even if 'invalid' if (ignoreReport(Loc.getSourceLocation(), Opts)) return; - if (Data->Loc.isInvalid()) + SymbolizedStackHolder FallbackLoc; + if (Data->Loc.isInvalid()) { + FallbackLoc.reset(getCallerLocation(Opts.pc)); Loc = FallbackLoc; + } ScopedReport R(Opts, Loc); if (!Pointer) Diag(Loc, DL_Error, "%0 null pointer of type %1") << TypeCheckKinds[Data->TypeCheckKind] << Data->Type; else if (Data->Alignment && (Pointer & (Data->Alignment - 1))) Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, " "which requires %2 byte alignment") << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Alignment << Data->Type; else Diag(Loc, DL_Error, "%0 address %1 with insufficient space " "for an object of type %2") << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type; if (Pointer) Diag(Pointer, DL_Note, "pointer points here"); } void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data, ValueHandle Pointer) { GET_REPORT_OPTIONS(false); - handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), Opts); + handleTypeMismatchImpl(Data, Pointer, Opts); } void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData *Data, ValueHandle Pointer) { GET_REPORT_OPTIONS(true); - handleTypeMismatchImpl(Data, Pointer, getCallerLocation(), Opts); + handleTypeMismatchImpl(Data, Pointer, Opts); Die(); } /// \brief Common diagnostic emission for various forms of integer overflow. template static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS, const char *Operator, T RHS, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); if (ignoreReport(Loc, Opts)) return; ScopedReport R(Opts, Loc); Diag(Loc, DL_Error, "%0 integer overflow: " "%1 %2 %3 cannot be represented in type %4") << (Data->Type.isSignedIntegerTy() ? "signed" : "unsigned") << Value(Data->Type, LHS) << Operator << RHS << Data->Type; } #define UBSAN_OVERFLOW_HANDLER(handler_name, op, abort) \ void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \ ValueHandle RHS) { \ GET_REPORT_OPTIONS(abort); \ handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \ if (abort) Die(); \ } UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false) UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow_abort, "+", true) UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "-", false) UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow_abort, "-", true) UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "*", false) UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true) static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); if (ignoreReport(Loc, Opts)) return; ScopedReport R(Opts, Loc); if (Data->Type.isSignedIntegerTy()) Diag(Loc, DL_Error, "negation of %0 cannot be represented in type %1; " "cast to an unsigned type to negate this value to itself") << Value(Data->Type, OldVal) << Data->Type; else Diag(Loc, DL_Error, "negation of %0 cannot be represented in type %1") << Value(Data->Type, OldVal) << Data->Type; } void __ubsan::__ubsan_handle_negate_overflow(OverflowData *Data, ValueHandle OldVal) { GET_REPORT_OPTIONS(false); handleNegateOverflowImpl(Data, OldVal, Opts); } void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data, ValueHandle OldVal) { GET_REPORT_OPTIONS(true); handleNegateOverflowImpl(Data, OldVal, Opts); Die(); } static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS, ValueHandle RHS, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); if (ignoreReport(Loc, Opts)) return; ScopedReport R(Opts, Loc); Value LHSVal(Data->Type, LHS); Value RHSVal(Data->Type, RHS); if (RHSVal.isMinusOne()) Diag(Loc, DL_Error, "division of %0 by -1 cannot be represented in type %1") << LHSVal << Data->Type; else Diag(Loc, DL_Error, "division by zero"); } void __ubsan::__ubsan_handle_divrem_overflow(OverflowData *Data, ValueHandle LHS, ValueHandle RHS) { GET_REPORT_OPTIONS(false); handleDivremOverflowImpl(Data, LHS, RHS, Opts); } void __ubsan::__ubsan_handle_divrem_overflow_abort(OverflowData *Data, ValueHandle LHS, ValueHandle RHS) { GET_REPORT_OPTIONS(true); handleDivremOverflowImpl(Data, LHS, RHS, Opts); Die(); } static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data, ValueHandle LHS, ValueHandle RHS, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); if (ignoreReport(Loc, Opts)) return; ScopedReport R(Opts, Loc); Value LHSVal(Data->LHSType, LHS); Value RHSVal(Data->RHSType, RHS); if (RHSVal.isNegative()) Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal; else if (RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth()) Diag(Loc, DL_Error, "shift exponent %0 is too large for %1-bit type %2") << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType; else if (LHSVal.isNegative()) Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal; else Diag(Loc, DL_Error, "left shift of %0 by %1 places cannot be represented in type %2") << LHSVal << RHSVal << Data->LHSType; } void __ubsan::__ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *Data, ValueHandle LHS, ValueHandle RHS) { GET_REPORT_OPTIONS(false); handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts); } void __ubsan::__ubsan_handle_shift_out_of_bounds_abort( ShiftOutOfBoundsData *Data, ValueHandle LHS, ValueHandle RHS) { GET_REPORT_OPTIONS(true); handleShiftOutOfBoundsImpl(Data, LHS, RHS, Opts); Die(); } static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); if (ignoreReport(Loc, Opts)) return; ScopedReport R(Opts, Loc); Value IndexVal(Data->IndexType, Index); Diag(Loc, DL_Error, "index %0 out of bounds for type %1") << IndexVal << Data->ArrayType; } void __ubsan::__ubsan_handle_out_of_bounds(OutOfBoundsData *Data, ValueHandle Index) { GET_REPORT_OPTIONS(false); handleOutOfBoundsImpl(Data, Index, Opts); } void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data, ValueHandle Index) { GET_REPORT_OPTIONS(true); handleOutOfBoundsImpl(Data, Index, Opts); Die(); } static void handleBuiltinUnreachableImpl(UnreachableData *Data, ReportOptions Opts) { ScopedReport R(Opts, Data->Loc); Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call"); } void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) { GET_REPORT_OPTIONS(true); handleBuiltinUnreachableImpl(Data, Opts); Die(); } static void handleMissingReturnImpl(UnreachableData *Data, ReportOptions Opts) { ScopedReport R(Opts, Data->Loc); Diag(Data->Loc, DL_Error, "execution reached the end of a value-returning function " "without returning a value"); } void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) { GET_REPORT_OPTIONS(true); handleMissingReturnImpl(Data, Opts); Die(); } static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); if (ignoreReport(Loc, Opts)) return; ScopedReport R(Opts, Loc); Diag(Loc, DL_Error, "variable length array bound evaluates to " "non-positive value %0") << Value(Data->Type, Bound); } void __ubsan::__ubsan_handle_vla_bound_not_positive(VLABoundData *Data, ValueHandle Bound) { GET_REPORT_OPTIONS(false); handleVLABoundNotPositive(Data, Bound, Opts); } void __ubsan::__ubsan_handle_vla_bound_not_positive_abort(VLABoundData *Data, ValueHandle Bound) { GET_REPORT_OPTIONS(true); handleVLABoundNotPositive(Data, Bound, Opts); Die(); } static void handleFloatCastOverflow(FloatCastOverflowData *Data, ValueHandle From, ReportOptions Opts) { // TODO: Add deduplication once a SourceLocation is generated for this check. - Location Loc = getCallerLocation(); + SymbolizedStackHolder CallerLoc(getCallerLocation(Opts.pc)); + Location Loc = CallerLoc; ScopedReport R(Opts, Loc); Diag(Loc, DL_Error, "value %0 is outside the range of representable values of type %2") << Value(Data->FromType, From) << Data->FromType << Data->ToType; } void __ubsan::__ubsan_handle_float_cast_overflow(FloatCastOverflowData *Data, ValueHandle From) { GET_REPORT_OPTIONS(false); handleFloatCastOverflow(Data, From, Opts); } void __ubsan::__ubsan_handle_float_cast_overflow_abort(FloatCastOverflowData *Data, ValueHandle From) { GET_REPORT_OPTIONS(true); handleFloatCastOverflow(Data, From, Opts); Die(); } static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); if (ignoreReport(Loc, Opts)) return; ScopedReport R(Opts, Loc); Diag(Loc, DL_Error, "load of value %0, which is not a valid value for type %1") << Value(Data->Type, Val) << Data->Type; } void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data, ValueHandle Val) { GET_REPORT_OPTIONS(false); handleLoadInvalidValue(Data, Val, Opts); } void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data, ValueHandle Val) { GET_REPORT_OPTIONS(true); handleLoadInvalidValue(Data, Val, Opts); Die(); } static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data, ValueHandle Function, ReportOptions Opts) { - const char *FName = "(unknown)"; + SourceLocation CallLoc = Data->Loc.acquire(); + if (ignoreReport(CallLoc, Opts)) + return; - Location Loc = getFunctionLocation(Function, &FName); + ScopedReport R(Opts, CallLoc); - ScopedReport R(Opts, Loc); + SymbolizedStackHolder FLoc(getSymbolizedLocation(Function)); + const char *FName = FLoc.get()->info.function; + if (!FName) + FName = "(unknown)"; - Diag(Data->Loc, DL_Error, + Diag(CallLoc, DL_Error, "call to function %0 through pointer to incorrect function type %1") - << FName << Data->Type; - Diag(Loc, DL_Note, "%0 defined here") << FName; + << FName << Data->Type; + Diag(FLoc, DL_Note, "%0 defined here") << FName; } void __ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data, ValueHandle Function) { GET_REPORT_OPTIONS(false); handleFunctionTypeMismatch(Data, Function, Opts); } void __ubsan::__ubsan_handle_function_type_mismatch_abort( FunctionTypeMismatchData *Data, ValueHandle Function) { GET_REPORT_OPTIONS(true); handleFunctionTypeMismatch(Data, Function, Opts); Die(); } static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); if (ignoreReport(Loc, Opts)) return; ScopedReport R(Opts, Loc); Diag(Loc, DL_Error, "null pointer returned from function declared to never " "return null"); if (!Data->AttrLoc.isInvalid()) Diag(Data->AttrLoc, DL_Note, "returns_nonnull attribute specified here"); } void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) { GET_REPORT_OPTIONS(false); handleNonNullReturn(Data, Opts); } void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) { GET_REPORT_OPTIONS(true); handleNonNullReturn(Data, Opts); Die(); } static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); if (ignoreReport(Loc, Opts)) return; ScopedReport R(Opts, Loc); Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to " "never be null") << Data->ArgIndex; if (!Data->AttrLoc.isInvalid()) Diag(Data->AttrLoc, DL_Note, "nonnull attribute specified here"); } void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) { GET_REPORT_OPTIONS(false); handleNonNullArg(Data, Opts); } void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) { GET_REPORT_OPTIONS(true); handleNonNullArg(Data, Opts); Die(); } Index: projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cc (revision 279194) @@ -1,82 +1,81 @@ //===-- ubsan_handlers_cxx.cc ---------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Error logging entry points for the UBSan runtime, which are only used for C++ // compilations. This file is permitted to use language features which require // linking against a C++ ABI library. // //===----------------------------------------------------------------------===// #include "ubsan_handlers_cxx.h" #include "ubsan_diag.h" #include "ubsan_type_hash.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_suppressions.h" using namespace __sanitizer; using namespace __ubsan; namespace __ubsan { extern const char *TypeCheckKinds[]; } static void HandleDynamicTypeCacheMiss( DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash, ReportOptions Opts) { if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash)) // Just a cache miss. The type matches after all. return; // Check if error report should be suppressed. DynamicTypeInfo DTI = getDynamicTypeInfo((void*)Pointer); - if (DTI.isValid() && - MatchSuppression(DTI.getMostDerivedTypeName(), SuppressionVptrCheck)) + if (DTI.isValid() && IsVptrCheckSuppressed(DTI.getMostDerivedTypeName())) return; SourceLocation Loc = Data->Loc.acquire(); if (Loc.isDisabled()) return; ScopedReport R(Opts, Loc); Diag(Loc, DL_Error, "%0 address %1 which does not point to an object of type %2") << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type; // If possible, say what type it actually points to. if (!DTI.isValid()) Diag(Pointer, DL_Note, "object has invalid vptr") << MangledName(DTI.getMostDerivedTypeName()) << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr"); else if (!DTI.getOffset()) Diag(Pointer, DL_Note, "object is of type %0") << MangledName(DTI.getMostDerivedTypeName()) << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0"); else // FIXME: Find the type at the specified offset, and include that // in the note. Diag(Pointer - DTI.getOffset(), DL_Note, "object is base class subobject at offset %0 within object of type %1") << DTI.getOffset() << MangledName(DTI.getMostDerivedTypeName()) << MangledName(DTI.getSubobjectTypeName()) << Range(Pointer, Pointer + sizeof(uptr), "vptr for %2 base class of %1"); } void __ubsan::__ubsan_handle_dynamic_type_cache_miss( DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) { GET_REPORT_OPTIONS(false); HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts); } void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort( DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) { GET_REPORT_OPTIONS(true); HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts); } Index: projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_init.cc =================================================================== --- projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_init.cc (revision 279193) +++ projects/clang360-import/contrib/compiler-rt/lib/ubsan/ubsan_init.cc (revision 279194) @@ -1,63 +1,63 @@ //===-- ubsan_init.cc -----------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Initialization of UBSan runtime. // //===----------------------------------------------------------------------===// +#include "ubsan_diag.h" #include "ubsan_init.h" #include "ubsan_flags.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mutex.h" -#include "sanitizer_common/sanitizer_suppressions.h" #include "sanitizer_common/sanitizer_symbolizer.h" using namespace __ubsan; static bool ubsan_inited; void __ubsan::InitIfNecessary() { #if !SANITIZER_CAN_USE_PREINIT_ARRAY // No need to lock mutex if we're initializing from preinit array. static StaticSpinMutex init_mu; SpinMutexLock l(&init_mu); #endif if (LIKELY(ubsan_inited)) return; bool standalone = false; if (0 == internal_strcmp(SanitizerToolName, "SanitizerTool")) { // WARNING: If this condition holds, then either UBSan runs in a standalone // mode, or initializer for another sanitizer hasn't run yet. In a latter // case, another sanitizer will overwrite "SanitizerToolName" and reparse // common flags. It means, that we are not allowed to *use* common flags // in this function. SanitizerToolName = "UndefinedBehaviorSanitizer"; standalone = true; } // Initialize UBSan-specific flags. InitializeFlags(standalone); - SuppressionContext::InitIfNecessary(); + InitializeSuppressions(); InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); ubsan_inited = true; } #if SANITIZER_CAN_USE_PREINIT_ARRAY __attribute__((section(".preinit_array"), used)) void (*__local_ubsan_preinit)(void) = __ubsan::InitIfNecessary; #else // Use a dynamic initializer. class UbsanInitializer { public: UbsanInitializer() { InitIfNecessary(); } }; static UbsanInitializer ubsan_initializer; #endif // SANITIZER_CAN_USE_PREINIT_ARRAY Index: projects/clang360-import/contrib/compiler-rt =================================================================== --- projects/clang360-import/contrib/compiler-rt (revision 279193) +++ projects/clang360-import/contrib/compiler-rt (revision 279194) Property changes on: projects/clang360-import/contrib/compiler-rt ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /vendor/compiler-rt/dist:r279190-279193