diff options
Diffstat (limited to 'contrib/compiler-rt/lib/msan')
-rw-r--r-- | contrib/compiler-rt/lib/msan/msan.cc | 44 | ||||
-rw-r--r-- | contrib/compiler-rt/lib/msan/msan.h | 82 | ||||
-rw-r--r-- | contrib/compiler-rt/lib/msan/msan_allocator.cc | 36 | ||||
-rw-r--r-- | contrib/compiler-rt/lib/msan/msan_chained_origin_depot.cc | 10 | ||||
-rw-r--r-- | contrib/compiler-rt/lib/msan/msan_flags.inc | 4 | ||||
-rw-r--r-- | contrib/compiler-rt/lib/msan/msan_interceptors.cc | 90 | ||||
-rw-r--r-- | contrib/compiler-rt/lib/msan/msan_interface_internal.h | 14 | ||||
-rw-r--r-- | contrib/compiler-rt/lib/msan/msan_linux.cc | 23 | ||||
-rw-r--r-- | contrib/compiler-rt/lib/msan/msan_new_delete.cc | 4 | ||||
-rw-r--r-- | contrib/compiler-rt/lib/msan/msan_thread.h | 2 | ||||
-rw-r--r-- | contrib/compiler-rt/lib/msan/tests/msan_loadable.cc | 27 | ||||
-rw-r--r-- | contrib/compiler-rt/lib/msan/tests/msan_test.cc | 4287 | ||||
-rw-r--r-- | contrib/compiler-rt/lib/msan/tests/msan_test_config.h | 20 | ||||
-rw-r--r-- | contrib/compiler-rt/lib/msan/tests/msan_test_main.cc | 21 |
14 files changed, 227 insertions, 4437 deletions
diff --git a/contrib/compiler-rt/lib/msan/msan.cc b/contrib/compiler-rt/lib/msan/msan.cc index 163d59d..9949db4 100644 --- a/contrib/compiler-rt/lib/msan/msan.cc +++ b/contrib/compiler-rt/lib/msan/msan.cc @@ -55,7 +55,7 @@ SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u32 __msan_retval_origin_tls; SANITIZER_INTERFACE_ATTRIBUTE -THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)]; +ALIGNED(16) THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)]; SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL u64 __msan_va_arg_overflow_size_tls; @@ -90,8 +90,6 @@ 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; @@ -145,6 +143,7 @@ static void InitializeFlags() { // FIXME: test and enable. cf.check_printf = false; cf.intercept_tls_get_addr = true; + cf.exitcode = 77; OverrideCommonFlags(cf); } @@ -185,11 +184,18 @@ static void InitializeFlags() { 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(); + // Check if deprecated exit_code MSan flag is set. + if (f->exit_code != -1) { + if (Verbosity()) + Printf("MSAN_OPTIONS=exit_code is deprecated! " + "Please use MSAN_OPTIONS=exitcode instead.\n"); + CommonFlags cf; + cf.CopyFrom(*common_flags()); + cf.exitcode = f->exit_code; + OverrideCommonFlags(cf); } + + // Check flag values: if (f->origin_history_size < 0 || f->origin_history_size > Origin::kMaxDepth) { Printf( @@ -217,9 +223,9 @@ void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp, 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); + return stack->Unwind(max_s, pc, bp, nullptr, 0, 0, request_fast_unwind); } - stack->Unwind(max_s, pc, bp, 0, t->stack_top(), t->stack_bottom(), + stack->Unwind(max_s, pc, bp, nullptr, t->stack_top(), t->stack_bottom(), request_fast_unwind); } @@ -299,7 +305,7 @@ u32 ChainOrigin(u32 id, StackTrace *stack) { return chained.raw_id(); } -} // namespace __msan +} // namespace __msan // Interface. @@ -369,11 +375,11 @@ void __msan_init() { msan_init_is_running = 1; SanitizerToolName = "MemorySanitizer"; - SetDieCallback(MsanDie); InitTlsSize(); - InitializeFlags(); CacheBinaryName(); + InitializeFlags(); + __sanitizer_set_report_path(common_flags()->log_path); InitializeInterceptors(); @@ -407,7 +413,9 @@ void __msan_init() { MsanTSDInit(MsanTSDDtor); - MsanThread *main_thread = MsanThread::Create(0, 0); + MsanAllocatorInit(); + + MsanThread *main_thread = MsanThread::Create(nullptr, nullptr); SetCurrentThread(main_thread); main_thread->ThreadStart(); @@ -421,10 +429,6 @@ void __msan_init() { 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; } @@ -511,7 +515,7 @@ 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) { +void __msan_load_unpoisoned(const void *src, uptr size, void *dst) { internal_memcpy(dst, src, size); __msan_unpoison(dst, size); } @@ -619,7 +623,7 @@ void __sanitizer_unaligned_store64(uu64 *p, u64 x) { } void __msan_set_death_callback(void (*callback)(void)) { - death_callback = callback; + SetUserDieCallback(callback); } #if !SANITIZER_SUPPORTS_WEAK_HOOKS @@ -635,4 +639,4 @@ void __sanitizer_print_stack_trace() { GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME()); stack.Print(); } -} // extern "C" +} // extern "C" diff --git a/contrib/compiler-rt/lib/msan/msan.h b/contrib/compiler-rt/lib/msan/msan.h index cd8bc19..2079a59 100644 --- a/contrib/compiler-rt/lib/msan/msan.h +++ b/contrib/compiler-rt/lib/msan/msan.h @@ -52,6 +52,61 @@ const MappingDesc kMemoryLayout[] = { #define MEM_TO_SHADOW(mem) (((uptr)(mem)) & ~0x4000000000ULL) #define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x002000000000) +#elif SANITIZER_LINUX && defined(__aarch64__) + +// The mapping describes both 39-bits and 42-bits. AArch64 maps: +// - 0x00000000000-0x00010000000: 39/42-bits program own segments +// - 0x05500000000-0x05600000000: 39-bits PIE program segments +// - 0x07f80000000-0x07fffffffff: 39-bits libraries segments +// - 0x2aa00000000-0x2ab00000000: 42-bits PIE program segments +// - 0x3ff00000000-0x3ffffffffff: 42-bits libraries segments +// It is fragmented in multiples segments to increase the memory available +// on 42-bits (12.21% of total VMA available for 42-bits and 13.28 for +// 39 bits). +const MappingDesc kMemoryLayout[] = { + {0x00000000000ULL, 0x01000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x01000000000ULL, 0x02000000000ULL, MappingDesc::SHADOW, "shadow-2"}, + {0x02000000000ULL, 0x03000000000ULL, MappingDesc::ORIGIN, "origin-2"}, + {0x03000000000ULL, 0x04000000000ULL, MappingDesc::SHADOW, "shadow-1"}, + {0x04000000000ULL, 0x05000000000ULL, MappingDesc::ORIGIN, "origin-1"}, + {0x05000000000ULL, 0x06000000000ULL, MappingDesc::APP, "app-1"}, + {0x06000000000ULL, 0x07000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x07000000000ULL, 0x08000000000ULL, MappingDesc::APP, "app-2"}, + {0x08000000000ULL, 0x09000000000ULL, MappingDesc::INVALID, "invalid"}, + // The mappings below are used only for 42-bits VMA. + {0x09000000000ULL, 0x0A000000000ULL, MappingDesc::SHADOW, "shadow-3"}, + {0x0A000000000ULL, 0x0B000000000ULL, MappingDesc::ORIGIN, "origin-3"}, + {0x0B000000000ULL, 0x0F000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x0F000000000ULL, 0x10000000000ULL, MappingDesc::APP, "app-3"}, + {0x10000000000ULL, 0x11000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x11000000000ULL, 0x12000000000ULL, MappingDesc::APP, "app-4"}, + {0x12000000000ULL, 0x17000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x17000000000ULL, 0x18000000000ULL, MappingDesc::SHADOW, "shadow-4"}, + {0x18000000000ULL, 0x19000000000ULL, MappingDesc::ORIGIN, "origin-4"}, + {0x19000000000ULL, 0x20000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x20000000000ULL, 0x21000000000ULL, MappingDesc::APP, "app-5"}, + {0x21000000000ULL, 0x26000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x26000000000ULL, 0x27000000000ULL, MappingDesc::SHADOW, "shadow-5"}, + {0x27000000000ULL, 0x28000000000ULL, MappingDesc::ORIGIN, "origin-5"}, + {0x28000000000ULL, 0x29000000000ULL, MappingDesc::SHADOW, "shadow-7"}, + {0x29000000000ULL, 0x2A000000000ULL, MappingDesc::ORIGIN, "origin-7"}, + {0x2A000000000ULL, 0x2B000000000ULL, MappingDesc::APP, "app-6"}, + {0x2B000000000ULL, 0x2C000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x2C000000000ULL, 0x2D000000000ULL, MappingDesc::SHADOW, "shadow-6"}, + {0x2D000000000ULL, 0x2E000000000ULL, MappingDesc::ORIGIN, "origin-6"}, + {0x2E000000000ULL, 0x2F000000000ULL, MappingDesc::APP, "app-7"}, + {0x2F000000000ULL, 0x39000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x39000000000ULL, 0x3A000000000ULL, MappingDesc::SHADOW, "shadow-9"}, + {0x3A000000000ULL, 0x3B000000000ULL, MappingDesc::ORIGIN, "origin-9"}, + {0x3B000000000ULL, 0x3C000000000ULL, MappingDesc::APP, "app-8"}, + {0x3C000000000ULL, 0x3D000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x3D000000000ULL, 0x3E000000000ULL, MappingDesc::SHADOW, "shadow-8"}, + {0x3E000000000ULL, 0x3F000000000ULL, MappingDesc::ORIGIN, "origin-8"}, + {0x3F000000000ULL, 0x40000000000ULL, MappingDesc::APP, "app-9"}, +}; +# define MEM_TO_SHADOW(mem) ((uptr)mem ^ 0x6000000000ULL) +# define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x1000000000ULL) + #elif SANITIZER_LINUX && defined(__powerpc64__) const MappingDesc kMemoryLayout[] = { @@ -94,6 +149,7 @@ const MappingDesc kMemoryLayout[] = { #elif SANITIZER_LINUX && SANITIZER_WORDSIZE == 64 +#ifdef MSAN_LINUX_X86_64_OLD_MAPPING // Requries PIE binary and ASLR enabled. // Main thread stack and DSOs at 0x7f0000000000 (sometimes 0x7e0000000000). // Heap at 0x600000000000. @@ -105,6 +161,28 @@ const MappingDesc kMemoryLayout[] = { #define MEM_TO_SHADOW(mem) (((uptr)(mem)) & ~0x400000000000ULL) #define SHADOW_TO_ORIGIN(mem) (((uptr)(mem)) + 0x200000000000ULL) +#else // MSAN_LINUX_X86_64_OLD_MAPPING +// All of the following configurations are supported. +// ASLR disabled: main executable and DSOs at 0x555550000000 +// PIE and ASLR: main executable and DSOs at 0x7f0000000000 +// non-PIE: main executable below 0x100000000, DSOs at 0x7f0000000000 +// Heap at 0x700000000000. +const MappingDesc kMemoryLayout[] = { + {0x000000000000ULL, 0x010000000000ULL, MappingDesc::APP, "app-1"}, + {0x010000000000ULL, 0x100000000000ULL, MappingDesc::SHADOW, "shadow-2"}, + {0x100000000000ULL, 0x110000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x110000000000ULL, 0x200000000000ULL, MappingDesc::ORIGIN, "origin-2"}, + {0x200000000000ULL, 0x300000000000ULL, MappingDesc::SHADOW, "shadow-3"}, + {0x300000000000ULL, 0x400000000000ULL, MappingDesc::ORIGIN, "origin-3"}, + {0x400000000000ULL, 0x500000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x500000000000ULL, 0x510000000000ULL, MappingDesc::SHADOW, "shadow-1"}, + {0x510000000000ULL, 0x600000000000ULL, MappingDesc::APP, "app-2"}, + {0x600000000000ULL, 0x610000000000ULL, MappingDesc::ORIGIN, "origin-1"}, + {0x610000000000ULL, 0x700000000000ULL, MappingDesc::INVALID, "invalid"}, + {0x700000000000ULL, 0x800000000000ULL, MappingDesc::APP, "app-3"}}; +#define MEM_TO_SHADOW(mem) (((uptr)(mem)) ^ 0x500000000000ULL) +#define SHADOW_TO_ORIGIN(mem) (((uptr)(mem)) + 0x100000000000ULL) +#endif // MSAN_LINUX_X86_64_OLD_MAPPING #else #error "Unsupported platform" @@ -148,6 +226,7 @@ bool InitShadow(bool init_origins); char *GetProcSelfMaps(); void InitializeInterceptors(); +void MsanAllocatorInit(); void MsanAllocatorThreadFinish(); void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size); void *MsanReallocate(StackTrace *stack, void *oldp, uptr size, @@ -167,7 +246,6 @@ struct SymbolizerScope { ~SymbolizerScope() { ExitSymbolizer(); } }; -void MsanDie(); void PrintWarning(uptr pc, uptr bp); void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin); @@ -224,8 +302,6 @@ class ScopedThreadLocalStateBackup { u64 va_arg_overflow_size_tls; }; -extern void (*death_callback)(void); - void MsanTSDInit(void (*destructor)(void *tsd)); void *MsanTSDGet(); void MsanTSDSet(void *tsd); diff --git a/contrib/compiler-rt/lib/msan/msan_allocator.cc b/contrib/compiler-rt/lib/msan/msan_allocator.cc index 6df3566..b7d3947 100644 --- a/contrib/compiler-rt/lib/msan/msan_allocator.cc +++ b/contrib/compiler-rt/lib/msan/msan_allocator.cc @@ -49,15 +49,21 @@ struct MsanMapUnmapCallback { typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(Metadata), SizeClassMap, kRegionSizeLog, ByteMap, MsanMapUnmapCallback> PrimaryAllocator; + #elif defined(__x86_64__) +#if SANITIZER_LINUX && !defined(MSAN_LINUX_X86_64_OLD_MAPPING) + static const uptr kAllocatorSpace = 0x700000000000ULL; +#else static const uptr kAllocatorSpace = 0x600000000000ULL; - static const uptr kAllocatorSize = 0x80000000000; // 8T. +#endif + static const uptr kAllocatorSize = 0x80000000000; // 8T. static const uptr kMetadataSize = sizeof(Metadata); static const uptr kMaxAllowedMallocSize = 8UL << 30; typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize, DefaultSizeClassMap, MsanMapUnmapCallback> PrimaryAllocator; + #elif defined(__powerpc64__) static const uptr kAllocatorSpace = 0x300000000000; static const uptr kAllocatorSize = 0x020000000000; // 2T @@ -67,6 +73,16 @@ struct MsanMapUnmapCallback { typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize, DefaultSizeClassMap, MsanMapUnmapCallback> PrimaryAllocator; +#elif defined(__aarch64__) + static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G + 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(Metadata), + SizeClassMap, kRegionSizeLog, ByteMap, + MsanMapUnmapCallback> PrimaryAllocator; #endif typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache; typedef LargeMmapAllocator<MsanMapUnmapCallback> SecondaryAllocator; @@ -77,12 +93,7 @@ static Allocator allocator; static AllocatorCache fallback_allocator_cache; static SpinMutex fallback_mutex; -static int inited = 0; - -static inline void Init() { - if (inited) return; - __msan_init(); - inited = true; // this must happen before any threads are created. +void MsanAllocatorInit() { allocator.Init(common_flags()->allocator_may_return_null); } @@ -98,7 +109,6 @@ void MsanThreadLocalMallocStorage::CommitBack() { static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment, bool zeroise) { - Init(); if (size > kMaxAllowedMallocSize) { Report("WARNING: MemorySanitizer failed to allocate %p bytes\n", (void *)size); @@ -133,7 +143,6 @@ static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment, void MsanDeallocate(StackTrace *stack, void *p) { CHECK(p); - Init(); MSAN_FREE_HOOK(p); Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(p)); uptr size = meta->requested_size; @@ -160,10 +169,9 @@ void MsanDeallocate(StackTrace *stack, void *p) { } void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) { - Init(); if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return allocator.ReturnNullOrDie(); - return MsanReallocate(stack, 0, nmemb * size, sizeof(u64), true); + return MsanReallocate(stack, nullptr, nmemb * size, sizeof(u64), true); } void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size, @@ -172,7 +180,7 @@ void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size, return MsanAllocate(stack, new_size, alignment, zeroise); if (!new_size) { MsanDeallocate(stack, old_p); - return 0; + return nullptr; } Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(old_p)); uptr old_size = meta->requested_size; @@ -202,14 +210,14 @@ void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size, } static uptr AllocationSize(const void *p) { - if (p == 0) return 0; + if (!p) return 0; const void *beg = allocator.GetBlockBegin(p); if (beg != p) return 0; Metadata *b = (Metadata *)allocator.GetMetaData(p); return b->requested_size; } -} // namespace __msan +} // namespace __msan using namespace __msan; diff --git a/contrib/compiler-rt/lib/msan/msan_chained_origin_depot.cc b/contrib/compiler-rt/lib/msan/msan_chained_origin_depot.cc index c21e8e8..e2796fd 100644 --- a/contrib/compiler-rt/lib/msan/msan_chained_origin_depot.cc +++ b/contrib/compiler-rt/lib/msan/msan_chained_origin_depot.cc @@ -28,12 +28,15 @@ struct ChainedOriginDepotNode { u32 prev_id; typedef ChainedOriginDepotDesc args_type; + bool eq(u32 hash, const args_type &args) const { return here_id == args.here_id && prev_id == args.prev_id; } + static uptr storage_size(const args_type &args) { return sizeof(ChainedOriginDepotNode); } + /* This is murmur2 hash for the 64->32 bit case. It does not behave all that well because the keys have a very biased distribution (I've seen 7-element buckets with the table only 14% full). @@ -76,19 +79,22 @@ struct ChainedOriginDepotNode { here_id = args.here_id; prev_id = args.prev_id; } + args_type load() const { args_type ret = {here_id, prev_id}; return ret; } + struct Handle { ChainedOriginDepotNode *node_; - Handle() : node_(0) {} + Handle() : node_(nullptr) {} explicit Handle(ChainedOriginDepotNode *node) : node_(node) {} bool valid() { return node_; } u32 id() { return node_->id; } int here_id() { return node_->here_id; } int prev_id() { return node_->prev_id; } }; + Handle get_handle() { return Handle(this); } typedef Handle handle_type; @@ -123,4 +129,4 @@ void ChainedOriginDepotUnlockAll() { chainedOriginDepot.UnlockAll(); } -} // namespace __msan +} // namespace __msan diff --git a/contrib/compiler-rt/lib/msan/msan_flags.inc b/contrib/compiler-rt/lib/msan/msan_flags.inc index cb58ffc..a7ff6c5 100644 --- a/contrib/compiler-rt/lib/msan/msan_flags.inc +++ b/contrib/compiler-rt/lib/msan/msan_flags.inc @@ -17,13 +17,15 @@ // MSAN_FLAG(Type, Name, DefaultValue, Description) // See COMMON_FLAG in sanitizer_flags.inc for more details. -MSAN_FLAG(int, exit_code, 77, "") +MSAN_FLAG(int, exit_code, -1, + "DEPRECATED. Use exitcode from common flags instead.") MSAN_FLAG(int, origin_history_size, Origin::kMaxDepth, "") MSAN_FLAG(int, origin_history_per_stack_limit, 20000, "") MSAN_FLAG(bool, poison_heap_with_zeroes, false, "") MSAN_FLAG(bool, poison_stack_with_zeroes, false, "") MSAN_FLAG(bool, poison_in_malloc, true, "") MSAN_FLAG(bool, poison_in_free, true, "") +MSAN_FLAG(bool, poison_in_dtor, false, "") MSAN_FLAG(bool, report_umrs, true, "") MSAN_FLAG(bool, wrap_signals, true, "") MSAN_FLAG(bool, print_stats, false, "") diff --git a/contrib/compiler-rt/lib/msan/msan_interceptors.cc b/contrib/compiler-rt/lib/msan/msan_interceptors.cc index 6d5a056..fc28e08 100644 --- a/contrib/compiler-rt/lib/msan/msan_interceptors.cc +++ b/contrib/compiler-rt/lib/msan/msan_interceptors.cc @@ -166,7 +166,7 @@ INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) { GET_MALLOC_STACK_TRACE; CHECK_EQ(alignment & (alignment - 1), 0); CHECK_NE(memptr, 0); - *memptr = MsanReallocate(&stack, 0, size, alignment, false); + *memptr = MsanReallocate(&stack, nullptr, size, alignment, false); CHECK_NE(*memptr, 0); __msan_unpoison(memptr, sizeof(*memptr)); return 0; @@ -176,7 +176,7 @@ INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) { INTERCEPTOR(void *, memalign, SIZE_T boundary, SIZE_T size) { GET_MALLOC_STACK_TRACE; CHECK_EQ(boundary & (boundary - 1), 0); - void *ptr = MsanReallocate(&stack, 0, size, boundary, false); + void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false); return ptr; } #define MSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign) @@ -187,21 +187,21 @@ INTERCEPTOR(void *, memalign, SIZE_T boundary, SIZE_T size) { INTERCEPTOR(void *, aligned_alloc, SIZE_T boundary, SIZE_T size) { GET_MALLOC_STACK_TRACE; CHECK_EQ(boundary & (boundary - 1), 0); - void *ptr = MsanReallocate(&stack, 0, size, boundary, false); + void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false); return ptr; } INTERCEPTOR(void *, __libc_memalign, SIZE_T boundary, SIZE_T size) { GET_MALLOC_STACK_TRACE; CHECK_EQ(boundary & (boundary - 1), 0); - void *ptr = MsanReallocate(&stack, 0, size, boundary, false); + void *ptr = MsanReallocate(&stack, nullptr, size, boundary, false); DTLS_on_libc_memalign(ptr, size * boundary); return ptr; } INTERCEPTOR(void *, valloc, SIZE_T size) { GET_MALLOC_STACK_TRACE; - void *ptr = MsanReallocate(&stack, 0, size, GetPageSizeCached(), false); + void *ptr = MsanReallocate(&stack, nullptr, size, GetPageSizeCached(), false); return ptr; } @@ -214,7 +214,7 @@ INTERCEPTOR(void *, pvalloc, SIZE_T size) { // pvalloc(0) should allocate one page. size = PageSize; } - void *ptr = MsanReallocate(&stack, 0, size, PageSize, false); + void *ptr = MsanReallocate(&stack, nullptr, size, PageSize, false); return ptr; } #define MSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc) @@ -224,14 +224,14 @@ INTERCEPTOR(void *, pvalloc, SIZE_T size) { INTERCEPTOR(void, free, void *ptr) { GET_MALLOC_STACK_TRACE; - if (ptr == 0) return; + if (!ptr) return; MsanDeallocate(&stack, ptr); } #if !SANITIZER_FREEBSD INTERCEPTOR(void, cfree, void *ptr) { GET_MALLOC_STACK_TRACE; - if (ptr == 0) return; + if (!ptr) return; MsanDeallocate(&stack, ptr); } #define MSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree) @@ -245,9 +245,15 @@ INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { #if !SANITIZER_FREEBSD // This function actually returns a struct by value, but we can't unpoison a -// temporary! The following is equivalent on all supported platforms, and we -// have a test to confirm that. +// temporary! The following is equivalent on all supported platforms but +// aarch64 (which uses a different register for sret value). We have a test +// to confirm that. INTERCEPTOR(void, mallinfo, __sanitizer_mallinfo *sret) { +#ifdef __aarch64__ + uptr r8; + asm volatile("mov %0,x8" : "=r" (r8)); + sret = reinterpret_cast<__sanitizer_mallinfo*>(r8); +#endif REAL(memset)(sret, 0, sizeof(*sret)); __msan_unpoison(sret, sizeof(*sret)); } @@ -994,7 +1000,7 @@ INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) { INTERCEPTOR(void *, malloc, SIZE_T size) { GET_MALLOC_STACK_TRACE; - return MsanReallocate(&stack, 0, size, sizeof(u64), false); + return MsanReallocate(&stack, nullptr, size, sizeof(u64), false); } void __msan_allocated_memory(const void *data, uptr size) { @@ -1005,6 +1011,19 @@ void __msan_allocated_memory(const void *data, uptr size) { } } +void __msan_copy_shadow(void *dest, const void *src, uptr n) { + GET_STORE_STACK_TRACE; + MoveShadowAndOrigin(dest, src, n, &stack); +} + +void __sanitizer_dtor_callback(const void *data, uptr size) { + GET_MALLOC_STACK_TRACE; + if (flags()->poison_in_dtor) { + stack.tag = STACK_TRACE_TAG_POISON; + PoisonMemory(data, size, &stack); + } +} + INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, int fd, OFF_T offset) { if (msan_init_is_running) @@ -1015,7 +1034,7 @@ INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, *__errno_location() = errno_EINVAL; return (void *)-1; } else { - addr = 0; + addr = nullptr; } } void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); @@ -1033,7 +1052,7 @@ INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, *__errno_location() = errno_EINVAL; return (void *)-1; } else { - addr = 0; + addr = nullptr; } } void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); @@ -1069,7 +1088,7 @@ INTERCEPTOR(int, dladdr, void *addr, dlinfo *info) { INTERCEPTOR(char *, dlerror, int fake) { ENSURE_MSAN_INITED(); char *res = REAL(dlerror)(fake); - if (res != 0) __msan_unpoison(res, REAL(strlen)(res) + 1); + if (res) __msan_unpoison(res, REAL(strlen)(res) + 1); return res; } @@ -1084,6 +1103,8 @@ static int msan_dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size, void *data) { if (info) { __msan_unpoison(info, size); + if (info->dlpi_phdr && info->dlpi_phnum) + __msan_unpoison(info->dlpi_phdr, struct_ElfW_Phdr_sz * info->dlpi_phnum); if (info->dlpi_name) __msan_unpoison(info->dlpi_name, REAL(strlen)(info->dlpi_name) + 1); } @@ -1164,7 +1185,7 @@ INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act, CHECK_LT(signo, kMaxSignals); uptr old_cb = atomic_load(&sigactions[signo], memory_order_relaxed); __sanitizer_sigaction new_act; - __sanitizer_sigaction *pnew_act = act ? &new_act : 0; + __sanitizer_sigaction *pnew_act = act ? &new_act : nullptr; if (act) { REAL(memcpy)(pnew_act, act, sizeof(__sanitizer_sigaction)); uptr cb = (uptr)pnew_act->sigaction; @@ -1221,7 +1242,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*), void * param) { ENSURE_MSAN_INITED(); // for GetTlsSize() __sanitizer_pthread_attr_t myattr; - if (attr == 0) { + if (!attr) { pthread_attr_init(&myattr); attr = &myattr; } @@ -1327,6 +1348,28 @@ INTERCEPTOR(int, fork, void) { return pid; } +INTERCEPTOR(int, openpty, int *amaster, int *aslave, char *name, + const void *termp, const void *winp) { + ENSURE_MSAN_INITED(); + InterceptorScope interceptor_scope; + int res = REAL(openpty)(amaster, aslave, name, termp, winp); + if (!res) { + __msan_unpoison(amaster, sizeof(*amaster)); + __msan_unpoison(aslave, sizeof(*aslave)); + } + return res; +} + +INTERCEPTOR(int, forkpty, int *amaster, char *name, const void *termp, + const void *winp) { + ENSURE_MSAN_INITED(); + InterceptorScope interceptor_scope; + int res = REAL(forkpty)(amaster, name, termp, winp); + if (res != -1) + __msan_unpoison(amaster, sizeof(*amaster)); + return res; +} + struct MSanInterceptorContext { bool in_interceptor_scope; }; @@ -1338,7 +1381,7 @@ int OnExit() { return 0; } -} // namespace __msan +} // namespace __msan // A version of CHECK_UNPOISONED using a saved scope value. Used in common // interceptors. @@ -1391,10 +1434,11 @@ int OnExit() { } while (false) // FIXME #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit() -#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ - do { \ - link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE((handle)); \ - if (map) ForEachMappedRegion(map, __msan_unpoison); \ +#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ + do { \ + link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE((handle)); \ + if (filename && map) \ + ForEachMappedRegion(map, __msan_unpoison); \ } while (false) #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ @@ -1591,7 +1635,9 @@ void InitializeInterceptors() { INTERCEPT_FUNCTION(__cxa_atexit); INTERCEPT_FUNCTION(shmat); INTERCEPT_FUNCTION(fork); + INTERCEPT_FUNCTION(openpty); + INTERCEPT_FUNCTION(forkpty); inited = 1; } -} // namespace __msan +} // namespace __msan diff --git a/contrib/compiler-rt/lib/msan/msan_interface_internal.h b/contrib/compiler-rt/lib/msan/msan_interface_internal.h index f4d37d9..c1e02ce 100644 --- a/contrib/compiler-rt/lib/msan/msan_interface_internal.h +++ b/contrib/compiler-rt/lib/msan/msan_interface_internal.h @@ -27,7 +27,7 @@ SANITIZER_INTERFACE_ATTRIBUTE void __msan_init(); // Print a warning and maybe return. -// This function can die based on flags()->exit_code. +// This function can die based on common_flags()->exitcode. SANITIZER_INTERFACE_ATTRIBUTE void __msan_warning(); @@ -106,10 +106,6 @@ int __msan_origin_is_descendant_or_same(u32 this_id, u32 prev_id); SANITIZER_INTERFACE_ATTRIBUTE void __msan_clear_on_return(); -// Default: -1 (don't exit on error). -SANITIZER_INTERFACE_ATTRIBUTE -void __msan_set_exit_code(int exit_code); - SANITIZER_INTERFACE_ATTRIBUTE void __msan_set_keep_going(int keep_going); @@ -140,6 +136,11 @@ void __msan_partial_poison(const void* data, void* shadow, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __msan_allocated_memory(const void* data, uptr size); +// Tell MSan about newly destroyed memory. Memory will be marked +// uninitialized. +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_dtor_callback(const void* data, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE u16 __sanitizer_unaligned_load16(const uu16 *p); @@ -160,6 +161,9 @@ void __sanitizer_unaligned_store64(uu64 *p, u64 x); SANITIZER_INTERFACE_ATTRIBUTE void __msan_set_death_callback(void (*callback)(void)); + +SANITIZER_INTERFACE_ATTRIBUTE +void __msan_copy_shadow(void *dst, const void *src, uptr size); } // extern "C" #endif // MSAN_INTERFACE_INTERNAL_H diff --git a/contrib/compiler-rt/lib/msan/msan_linux.cc b/contrib/compiler-rt/lib/msan/msan_linux.cc index 7025ef6..ab3be91 100644 --- a/contrib/compiler-rt/lib/msan/msan_linux.cc +++ b/contrib/compiler-rt/lib/msan/msan_linux.cc @@ -56,7 +56,7 @@ static bool CheckMemoryRangeAvailability(uptr beg, uptr size) { static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) { if (size > 0) { void *addr = MmapNoAccess(beg, size, name); - if (beg == 0 && addr != 0) { + if (beg == 0 && addr) { // Depending on the kernel configuration, we may not be able to protect // the page at address zero. uptr gap = 16 * GetPageSizeCached(); @@ -119,12 +119,18 @@ bool InitShadow(bool init_origins) { return false; } + const uptr maxVirtualAddress = GetMaxVirtualAddress(); + for (unsigned i = 0; i < kMemoryLayoutSize; ++i) { uptr start = kMemoryLayout[i].start; uptr end = kMemoryLayout[i].end; uptr size= end - start; MappingDesc::Type type = kMemoryLayout[i].type; + // Check if the segment should be mapped based on platform constraints. + if (start >= maxVirtualAddress) + continue; + bool map = type == MappingDesc::SHADOW || (init_origins && type == MappingDesc::ORIGIN); bool protect = type == MappingDesc::INVALID || @@ -151,20 +157,13 @@ bool InitShadow(bool init_origins) { return true; } -void MsanDie() { - if (common_flags()->coverage) - __sanitizer_cov_dump(); - if (death_callback) - death_callback(); - internal__exit(flags()->exit_code); -} - static void MsanAtExit(void) { if (flags()->print_stats && (flags()->atexit || msan_report_count > 0)) ReportStats(); if (msan_report_count > 0) { ReportAtExitStatistics(); - if (flags()->exit_code) _exit(flags()->exit_code); + if (common_flags()->exitcode) + internal__exit(common_flags()->exitcode); } } @@ -211,6 +210,6 @@ void MsanTSDDtor(void *tsd) { MsanThread::TSDDtor(tsd); } -} // namespace __msan +} // namespace __msan -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/contrib/compiler-rt/lib/msan/msan_new_delete.cc b/contrib/compiler-rt/lib/msan/msan_new_delete.cc index c8bc065..5401003 100644 --- a/contrib/compiler-rt/lib/msan/msan_new_delete.cc +++ b/contrib/compiler-rt/lib/msan/msan_new_delete.cc @@ -45,9 +45,9 @@ void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; } if (ptr) MsanDeallocate(&stack, ptr) INTERCEPTOR_ATTRIBUTE -void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY; } +void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } INTERCEPTOR_ATTRIBUTE -void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY; } +void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } INTERCEPTOR_ATTRIBUTE void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; } INTERCEPTOR_ATTRIBUTE diff --git a/contrib/compiler-rt/lib/msan/msan_thread.h b/contrib/compiler-rt/lib/msan/msan_thread.h index bc605b8..ed22e67 100644 --- a/contrib/compiler-rt/lib/msan/msan_thread.h +++ b/contrib/compiler-rt/lib/msan/msan_thread.h @@ -32,7 +32,7 @@ class MsanThread { uptr stack_bottom() { return stack_bottom_; } uptr tls_begin() { return tls_begin_; } uptr tls_end() { return tls_end_; } - bool IsMainThread() { return start_routine_ == 0; } + bool IsMainThread() { return start_routine_ == nullptr; } bool AddrIsInStack(uptr addr) { return addr >= stack_bottom_ && addr < stack_top_; diff --git a/contrib/compiler-rt/lib/msan/tests/msan_loadable.cc b/contrib/compiler-rt/lib/msan/tests/msan_loadable.cc deleted file mode 100644 index 06e880f..0000000 --- a/contrib/compiler-rt/lib/msan/tests/msan_loadable.cc +++ /dev/null @@ -1,27 +0,0 @@ -//===-- msan_loadable.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. -//===----------------------------------------------------------------------===// - -#include "msan/msan_interface_internal.h" -#include <stdlib.h> - -static void *dso_global; - -// No name mangling. -extern "C" { - -void **get_dso_global() { - return &dso_global; -} - -} diff --git a/contrib/compiler-rt/lib/msan/tests/msan_test.cc b/contrib/compiler-rt/lib/msan/tests/msan_test.cc deleted file mode 100644 index 00dd20a..0000000 --- a/contrib/compiler-rt/lib/msan/tests/msan_test.cc +++ /dev/null @@ -1,4287 +0,0 @@ -//===-- 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 <sys/shm.h> -# undef _KERNEL -extern "C" { -// <sys/shm.h> 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 <inttypes.h> -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <wchar.h> -#include <math.h> - -#include <arpa/inet.h> -#include <dlfcn.h> -#include <grp.h> -#include <unistd.h> -#include <link.h> -#include <limits.h> -#include <sys/time.h> -#include <poll.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/resource.h> -#include <sys/ioctl.h> -#include <sys/statvfs.h> -#include <sys/utsname.h> -#include <sys/mman.h> -#include <dirent.h> -#include <pwd.h> -#include <sys/socket.h> -#include <netdb.h> -#include <wordexp.h> -#include <sys/ipc.h> -#include <sys/shm.h> - -#if !defined(__FreeBSD__) -# include <malloc.h> -# include <sys/sysinfo.h> -# include <sys/vfs.h> -# include <mntent.h> -# include <netinet/ether.h> -#else -# include <signal.h> -# include <netinet/in.h> -# include <pthread_np.h> -# include <sys/uio.h> -# include <sys/mount.h> -# include <sys/sysctl.h> -# include <net/ethernet.h> -# define f_namelen f_namemax // FreeBSD names this statfs field so. -# define cpu_set_t cpuset_t -extern "C" { -// FreeBSD's <ssp/string.h> 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 <emmintrin.h> -# define MSAN_HAS_M128 1 -#else -# define MSAN_HAS_M128 0 -#endif - -#ifdef __AVX2__ -# include <immintrin.h> -#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 - -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 __msan_origin_is_descendant_or_same(origin, 0x1234); -} - -#define EXPECT_ORIGIN(expected, origin) \ - EXPECT_TRUE(__msan_origin_is_descendant_or_same((origin), (expected))) - -#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_ORIGIN(origin, __msan_get_umr_origin()); \ - } while (0) - -#define EXPECT_POISONED(x) ExpectPoisoned(x) - -template<typename T> -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<typename T> -void ExpectPoisonedWithOrigin(const T& t, unsigned origin) { - EXPECT_NE(-1, __msan_test_shadow((void*)&t, sizeof(t))); - if (TrackingOrigins()) EXPECT_ORIGIN(origin, __msan_get_origin((void *)&t)); -} - -#define EXPECT_NOT_POISONED(x) EXPECT_EQ(true, TestForNotPoisoned((x))) - -template<typename T> -bool TestForNotPoisoned(const T& t) { - return __msan_test_shadow((void*)&t, sizeof(t)) == -1; -} - -static U8 poisoned_array[100]; -template<class T> -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<class T> -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<typename T> -T Poisoned(T v = 0, T s = (T)(-1)) { - __msan_partial_poison(&v, &s, sizeof(T)); - return v; -} - -template<class T> NOINLINE T ReturnPoisoned() { return *GetPoisoned<T>(); } - -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<S4>(); - if (g_one) - *x = 0; - EXPECT_NOT_POISONED(*x); -} - -TEST(MemorySanitizer, PositiveTest1) { - // Load to store. - EXPECT_POISONED(*GetPoisoned<S1>()); - EXPECT_POISONED(*GetPoisoned<S2>()); - EXPECT_POISONED(*GetPoisoned<S4>()); - EXPECT_POISONED(*GetPoisoned<S8>()); - - // S->S conversions. - EXPECT_POISONED(*GetPoisoned<S1>()); - EXPECT_POISONED(*GetPoisoned<S1>()); - EXPECT_POISONED(*GetPoisoned<S1>()); - - EXPECT_POISONED(*GetPoisoned<S2>()); - EXPECT_POISONED(*GetPoisoned<S2>()); - EXPECT_POISONED(*GetPoisoned<S2>()); - - EXPECT_POISONED(*GetPoisoned<S4>()); - EXPECT_POISONED(*GetPoisoned<S4>()); - EXPECT_POISONED(*GetPoisoned<S4>()); - - EXPECT_POISONED(*GetPoisoned<S8>()); - EXPECT_POISONED(*GetPoisoned<S8>()); - EXPECT_POISONED(*GetPoisoned<S8>()); - - // ZExt - EXPECT_POISONED(*GetPoisoned<U1>()); - EXPECT_POISONED(*GetPoisoned<U1>()); - EXPECT_POISONED(*GetPoisoned<U1>()); - EXPECT_POISONED(*GetPoisoned<U2>()); - EXPECT_POISONED(*GetPoisoned<U2>()); - EXPECT_POISONED(*GetPoisoned<U4>()); - - // Unary ops. - EXPECT_POISONED(- *GetPoisoned<S4>()); - - EXPECT_UMR(a_s4[g_zero] = 100 / *GetPoisoned<S4>(0, 1)); - - - a_s4[g_zero] = 1 - *GetPoisoned<S4>(); - a_s4[g_zero] = 1 + *GetPoisoned<S4>(); -} - -TEST(MemorySanitizer, Phi1) { - S4 c; - if (g_one) { - c = *GetPoisoned<S4>(); - } else { - break_optimization(0); - c = 0; - } - EXPECT_POISONED(c); -} - -TEST(MemorySanitizer, Phi2) { - S4 i = *GetPoisoned<S4>(); - 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<S4>()); - Arg2ExpectUMR(0, *GetPoisoned<S4>()); - Arg3ExpectUMR(0, 1, *GetPoisoned<S8>()); -} - - -TEST(MemorySanitizer, CallAndRet) { - ReturnPoisoned<S1>(); - ReturnPoisoned<S2>(); - ReturnPoisoned<S4>(); - ReturnPoisoned<S8>(); - - EXPECT_POISONED(ReturnPoisoned<S1>()); - EXPECT_POISONED(ReturnPoisoned<S2>()); - EXPECT_POISONED(ReturnPoisoned<S4>()); - EXPECT_POISONED(ReturnPoisoned<S8>()); -} - -// 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<U4>(); - // 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<bool>() & *GetPoisoned<bool>()); -} - -template<class T> -static bool applyNot(T value, T shadow) { - __msan_partial_poison(&value, &shadow, sizeof(T)); - return !value; -} - -TEST(MemorySanitizer, Not) { - EXPECT_NOT_POISONED(applyNot<U4>(0x0, 0x0)); - EXPECT_NOT_POISONED(applyNot<U4>(0xFFFFFFFF, 0x0)); - EXPECT_POISONED(applyNot<U4>(0xFFFFFFFF, 0xFFFFFFFF)); - EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x0FFFFFFF)); - EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x00FFFFFF)); - EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x0000FFFF)); - EXPECT_NOT_POISONED(applyNot<U4>(0xFF000000, 0x00000000)); - EXPECT_POISONED(applyNot<U4>(0xFF000000, 0xFF000000)); - EXPECT_NOT_POISONED(applyNot<U4>(0xFF800000, 0xFF000000)); - EXPECT_POISONED(applyNot<U4>(0x00008000, 0x00008000)); - - EXPECT_NOT_POISONED(applyNot<U1>(0x0, 0x0)); - EXPECT_NOT_POISONED(applyNot<U1>(0xFF, 0xFE)); - EXPECT_NOT_POISONED(applyNot<U1>(0xFF, 0x0)); - EXPECT_POISONED(applyNot<U1>(0xFF, 0xFF)); - - EXPECT_POISONED(applyNot<void*>((void*)0xFFFFFF, (void*)(-1))); - EXPECT_NOT_POISONED(applyNot<void*>((void*)0xFFFFFF, (void*)(-2))); -} - -TEST(MemorySanitizer, Shift) { - U4 *up = GetPoisoned<U4>(); - ((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<S4>(); - ((S1*)sp)[1] = 0; - ((S1*)sp)[2] = 0; - EXPECT_POISONED(*sp >> 31); - - EXPECT_POISONED(100 >> *GetPoisoned<S4>()); - EXPECT_POISONED(100U >> *GetPoisoned<S4>()); -} - -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<class T> -void TestFloatingPoint() { - static volatile T v; - static T g[100]; - break_optimization(&g); - T *x = GetPoisoned<T>(); - T *y = GetPoisoned<T>(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<float>(); - TestFloatingPoint<double>(); -} - -TEST(MemorySanitizer, DynMem) { - S4 x = 0; - S4 *y = GetPoisoned<S4>(); - memcpy(y, &x, g_one * sizeof(S4)); - EXPECT_NOT_POISONED(*y); -} - -static char *DynRetTestStr; - -TEST(MemorySanitizer, DynRet) { - ReturnPoisoned<S8>(); - EXPECT_NOT_POISONED(atoi("0")); -} - -TEST(MemorySanitizer, DynRet1) { - ReturnPoisoned<S8>(); -} - -struct LargeStruct { - S4 x[10]; -}; - -NOINLINE -LargeStruct LargeRetTest() { - LargeStruct res; - res.x[0] = *GetPoisoned<S4>(); - res.x[1] = *GetPoisoned<S4>(); - res.x[2] = *GetPoisoned<S4>(); - res.x[3] = *GetPoisoned<S4>(); - res.x[4] = *GetPoisoned<S4>(); - res.x[5] = *GetPoisoned<S4>(); - res.x[6] = *GetPoisoned<S4>(); - res.x[7] = *GetPoisoned<S4>(); - res.x[8] = *GetPoisoned<S4>(); - res.x[9] = *GetPoisoned<S4>(); - 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<U1>(); - ((char *)p)[4095] = *GetPoisoned<U1>(); - - 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<char>(); - 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<char>(); - 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<char>(); - 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<class T, int size> -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<U1, 10>(); - TestOverlapMemmove<U1, 1000>(); - TestOverlapMemmove<U8, 4>(); - TestOverlapMemmove<U8, 1000>(); -} - -TEST(MemorySanitizer, strcpy) { // NOLINT - char* x = new char[3]; - char* y = new char[3]; - x[0] = 'a'; - x[1] = *GetPoisoned<char>(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<char>(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<char>(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<int>(); - double r = frexp(1.1, &x); - EXPECT_NOT_POISONED(r); - EXPECT_NOT_POISONED(x); - - x = *GetPoisoned<int>(); - float rf = frexpf(1.1, &x); - EXPECT_NOT_POISONED(rf); - EXPECT_NOT_POISONED(x); - - x = *GetPoisoned<int>(); - 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<int>()); - EXPECT_NOT_POISONED(0); - EXPECT_POISONED(*GetPoisoned<int>()); - EXPECT_POISONED(ReturnPoisoned<S4>()); -} - -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<double>()); - EXPECT_NOT_POISONED(va_arg(vl, int)); - EXPECT_POISONED(va_arg(vl, int)); - va_end(vl); -} - -TEST(MemorySanitizer, VAArgTest) { - int* x = GetPoisoned<int>(); - int* y = GetPoisoned<int>(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>(); - int* y = GetPoisoned<int>(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>(); - int* y = GetPoisoned<int>(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>(); - int* y = GetPoisoned<int>(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<int*>(); - double** y = GetPoisoned<double*>(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<int>(); - double* y = GetPoisoned<double>(8); - int** p = GetPoisoned<int*>(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<int>(); - 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<int>(); - s.c = 2; - s.d = *GetPoisoned<int>(); - s.e = 3; - s.f = *GetPoisoned<int>(); - 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<int>(); - s.c = 2; - s.d = *GetPoisoned<int>(); - s.e = 3; - s.f = *GetPoisoned<int>(); - 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 <class T> -NOINLINE T ReturnStruct() { - T res; - __msan_poison(&res, sizeof(res)); - res.a = 1; - return res; -} - -template <class T> -NOINLINE void TestReturnStruct() { - T s1 = ReturnStruct<T>(); - 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<SSS1>(); - TestReturnStruct<SSS2>(); - TestReturnStruct<SSS3>(); - TestReturnStruct<SSS4>(); - TestReturnStruct<SSS5>(); - TestReturnStruct<SSS6>(); - TestReturnStruct<SSS7>(); - TestReturnStruct<SSS8>(); -} - -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); -} - -#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 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[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[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.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<SignalCondArg *>(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(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<class T> -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<S4>(0xF, 0xF)); - EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0xFF)); - EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0xFFFFFF)); - EXPECT_NOT_POISONED(applySlt<S4>(0xF, 0x7FFFFFF)); - EXPECT_UMR(applySlt<S4>(0xF, 0x80FFFFFF)); - EXPECT_UMR(applySlt<S4>(0xF, 0xFFFFFFFF)); -} - -template <class T, class S> -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] __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] __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); -} - -TEST(MemorySanitizer, UnalignedStore32) { - 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] __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] __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] __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] __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] __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<U2>(0, 3), Poisoned<U2>(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<U4>()); - 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<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7}; - // Top 64 bits of shift count don't affect the result. - V2x64 s = {2, Poisoned<U8>()}; - 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<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3, 4, 5, 6, 7}; - V2x64 s = {Poisoned<U8>(), Poisoned<U8>()}; - 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<U2>(0, 3), Poisoned<U2>(0, 7), 2, 3}; - V4x32 s = {2, Poisoned<U4>(), 3, Poisoned<U4>()}; - 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<U4>(0, 0xFF0000), Poisoned<U4>(0, 0xFFFF0000), - S2_max + 100, 4}; - V4x32 b = {Poisoned<U4>(0, 0xFF), S2_max + 10000, Poisoned<U4>(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<U2>(0, 0xFF00), Poisoned<U2>(0, 0xF000U), U1_max + 100, - 4}; - V4x16 b = {Poisoned<U2>(0, 0xFF), U1_max - 1, Poisoned<U2>(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<U1>(), 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<U2>(), 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_ORIGIN(1234U, __msan_get_origin(&x)); - __msan_set_origin(&x, sizeof(x), 5678); - EXPECT_ORIGIN(5678U, __msan_get_origin(&x)); - __msan_set_origin(&x, sizeof(x), 0); - EXPECT_ORIGIN(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<U2>(0, origin); - EXPECT_ORIGIN(origin, __msan_get_origin(&s.a)); - EXPECT_ORIGIN(origin, __msan_get_origin(&s.b)); - - s.b = 42; - EXPECT_ORIGIN(origin, __msan_get_origin(&s.a)); - EXPECT_ORIGIN(origin, __msan_get_origin(&s.b)); -} -} // namespace - -template<class T, class BinaryOp> -INLINE -void BinaryOpOriginTest(BinaryOp op) { - U4 ox = rand(); //NOLINT - U4 oy = rand(); //NOLINT - T *x = GetPoisonedO<T>(0, ox, 0); - T *y = GetPoisonedO<T>(1, oy, 0); - T *z = GetPoisonedO<T>(2, 0, 0); - - *z = op(*x, *y); - U4 origin = __msan_get_origin(z); - EXPECT_POISONED_O(*z, origin); - EXPECT_EQ(true, __msan_origin_is_descendant_or_same(origin, ox) || - __msan_origin_is_descendant_or_same(origin, oy)); - - // y is poisoned, x is not. - *x = 10101; - *y = *GetPoisonedO<T>(1, oy); - break_optimization(x); - __msan_set_origin(z, sizeof(*z), 0); - *z = op(*x, *y); - EXPECT_POISONED_O(*z, oy); - EXPECT_ORIGIN(oy, __msan_get_origin(z)); - - // x is poisoned, y is not. - *x = *GetPoisonedO<T>(0, ox); - *y = 10101010; - break_optimization(y); - __msan_set_origin(z, sizeof(*z), 0); - *z = op(*x, *y); - EXPECT_POISONED_O(*z, ox); - EXPECT_ORIGIN(ox, __msan_get_origin(z)); -} - -template<class T> INLINE T XOR(const T &a, const T&b) { return a ^ b; } -template<class T> INLINE T ADD(const T &a, const T&b) { return a + b; } -template<class T> INLINE T SUB(const T &a, const T&b) { return a - b; } -template<class T> INLINE T MUL(const T &a, const T&b) { return a * b; } -template<class T> INLINE T AND(const T &a, const T&b) { return a & b; } -template<class T> INLINE T OR (const T &a, const T&b) { return a | b; } - -TEST(MemorySanitizerOrigins, BinaryOp) { - if (!TrackingOrigins()) return; - BinaryOpOriginTest<S8>(XOR<S8>); - BinaryOpOriginTest<U8>(ADD<U8>); - BinaryOpOriginTest<S4>(SUB<S4>); - BinaryOpOriginTest<S4>(MUL<S4>); - BinaryOpOriginTest<U4>(OR<U4>); - BinaryOpOriginTest<U4>(AND<U4>); - BinaryOpOriginTest<double>(ADD<U4>); - BinaryOpOriginTest<float>(ADD<S4>); - BinaryOpOriginTest<double>(ADD<double>); - BinaryOpOriginTest<float>(ADD<double>); -} - -TEST(MemorySanitizerOrigins, Unary) { - if (!TrackingOrigins()) return; - EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__), __LINE__); - - EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); - - EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<U4>(0, __LINE__), __LINE__); - - EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); - - EXPECT_POISONED_O((void*)*GetPoisonedO<S8>(0, __LINE__), __LINE__); - EXPECT_POISONED_O((U8)*GetPoisonedO<void*>(0, __LINE__), __LINE__); -} - -TEST(MemorySanitizerOrigins, EQ) { - if (!TrackingOrigins()) return; - EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__) <= 11, __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__) == 11, __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<float>(0, __LINE__) == 1.1, __LINE__); -} - -TEST(MemorySanitizerOrigins, DIV) { - if (!TrackingOrigins()) return; - EXPECT_POISONED_O(*GetPoisonedO<U8>(0, __LINE__) / 100, __LINE__); - unsigned o = __LINE__; - EXPECT_UMR_O(volatile unsigned y = 100 / *GetPoisonedO<S4>(0, o, 1), o); -} - -TEST(MemorySanitizerOrigins, SHIFT) { - if (!TrackingOrigins()) return; - EXPECT_POISONED_O(*GetPoisonedO<U8>(0, __LINE__) >> 10, __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__) >> 10, __LINE__); - EXPECT_POISONED_O(*GetPoisonedO<S8>(0, __LINE__) << 10, __LINE__); - EXPECT_POISONED_O(10U << *GetPoisonedO<U8>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(-10 >> *GetPoisonedO<S8>(0, __LINE__), __LINE__); - EXPECT_POISONED_O(-10 << *GetPoisonedO<S8>(0, __LINE__), __LINE__); -} - -template<class T, int N> -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<U1, 10000>(); - MemCpyTest<U8, 10000>(); -} - -TEST(MemorySanitizerOrigins, SmallMemCpy) { - if (!TrackingOrigins()) return; - MemCpyTest<U8, 1>(); - MemCpyTest<U8, 2>(); - MemCpyTest<U8, 3>(); -} - -TEST(MemorySanitizerOrigins, Select) { - if (!TrackingOrigins()) return; - EXPECT_NOT_POISONED(g_one ? 1 : *GetPoisonedO<S4>(0, __LINE__)); - EXPECT_POISONED_O(*GetPoisonedO<S4>(0, __LINE__), __LINE__); - S4 x; - break_optimization(&x); - x = g_1 ? *GetPoisonedO<S4>(0, __LINE__) : 0; - - EXPECT_POISONED_O(g_1 ? *GetPoisonedO<S4>(0, __LINE__) : 1, __LINE__); - EXPECT_POISONED_O(g_0 ? 1 : *GetPoisonedO<S4>(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<char*>(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<void*>(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 diff --git a/contrib/compiler-rt/lib/msan/tests/msan_test_config.h b/contrib/compiler-rt/lib/msan/tests/msan_test_config.h deleted file mode 100644 index 5404c43..0000000 --- a/contrib/compiler-rt/lib/msan/tests/msan_test_config.h +++ /dev/null @@ -1,20 +0,0 @@ -//===-- msan_test_config.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 MemorySanitizer. -// -// MemorySanitizer unit tests. -//===----------------------------------------------------------------------===// - -#ifndef MSAN_TEST_CONFIG_H -#define MSAN_TEST_CONFIG_H - -#include "gtest/gtest.h" - -#endif // MSAN_TEST_CONFIG_H diff --git a/contrib/compiler-rt/lib/msan/tests/msan_test_main.cc b/contrib/compiler-rt/lib/msan/tests/msan_test_main.cc deleted file mode 100644 index c8c5fef..0000000 --- a/contrib/compiler-rt/lib/msan/tests/msan_test_main.cc +++ /dev/null @@ -1,21 +0,0 @@ -//===-- msan_test_main.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. -// -//===----------------------------------------------------------------------===// -#ifndef MSAN_EXTERNAL_TEST_CONFIG -#include "msan_test_config.h" -#endif // MSAN_EXTERNAL_TEST_CONFIG - -int main(int argc, char **argv) { - testing::GTEST_FLAG(death_test_style) = "threadsafe"; - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} |