Index: compiler-rt/lib/asan/asan_linux.cc =================================================================== --- compiler-rt/lib/asan/asan_linux.cc +++ compiler-rt/lib/asan/asan_linux.cc @@ -210,6 +210,8 @@ } } else { if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { + if (!MemoryMappingLayout::IsAvailable(/*cache_enabled*/true)) + return; // Ensure that dynamic runtime is not present. We should detect it // as early as possible, otherwise ASan interceptors could bind to // the functions in dynamic ASan runtime instead of the functions in Index: compiler-rt/lib/asan/asan_thread.cc =================================================================== --- compiler-rt/lib/asan/asan_thread.cc +++ compiler-rt/lib/asan/asan_thread.cc @@ -18,6 +18,7 @@ #include "asan_thread.h" #include "asan_mapping.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" @@ -223,9 +224,11 @@ atomic_store(&stack_switching_, false, memory_order_release); CHECK_EQ(this->stack_size(), 0U); SetThreadStackAndTls(options); - CHECK_GT(this->stack_size(), 0U); - CHECK(AddrIsInMem(stack_bottom_)); - CHECK(AddrIsInMem(stack_top_ - 1)); + if (stack_top_ != stack_bottom_) { + CHECK_GT(this->stack_size(), 0U); + CHECK(AddrIsInMem(stack_bottom_)); + CHECK(AddrIsInMem(stack_top_ - 1)); + } ClearShadowForThreadStackAndTLS(); fake_stack_ = nullptr; if (__asan_option_detect_stack_use_after_return) @@ -287,22 +290,30 @@ // OS-specific implementations that need more information passed through. void AsanThread::SetThreadStackAndTls(const InitOptions *options) { DCHECK_EQ(options, nullptr); - uptr tls_size = 0; - uptr stack_size = 0; - GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_, - &tls_size); - stack_top_ = stack_bottom_ + stack_size; - tls_end_ = tls_begin_ + tls_size; - dtls_ = DTLS_Get(); - - int local; - CHECK(AddrIsInStack((uptr)&local)); + // If this process is "init" (pid 1), /proc may not be mounted yet. + if (!start_routine_ && + !MemoryMappingLayout::IsAvailable(/*cache_enabled*/ true)) { + stack_top_ = stack_bottom_ = 0; + tls_begin_ = tls_end_ = 0; + } else { + uptr tls_size = 0; + uptr stack_size = 0; + GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_, + &tls_size); + stack_top_ = stack_bottom_ + stack_size; + tls_end_ = tls_begin_ + tls_size; + dtls_ = DTLS_Get(); + + int local; + CHECK(AddrIsInStack((uptr)&local)); + } } #endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS void AsanThread::ClearShadowForThreadStackAndTLS() { - PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); + if (stack_top_ != stack_bottom_) + PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); if (tls_begin_ != tls_end_) { uptr tls_begin_aligned = RoundDownTo(tls_begin_, SHADOW_GRANULARITY); uptr tls_end_aligned = RoundUpTo(tls_end_, SHADOW_GRANULARITY); @@ -314,6 +325,9 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access) { + if (stack_top_ == stack_bottom_) + return false; + uptr bottom = 0; if (AddrIsInStack(addr)) { bottom = stack_bottom(); Index: compiler-rt/lib/hwasan/hwasan_thread.cc =================================================================== --- compiler-rt/lib/hwasan/hwasan_thread.cc +++ compiler-rt/lib/hwasan/hwasan_thread.cc @@ -44,7 +44,8 @@ ScopedTaggingDisabler disabler; // If this process is "init" (pid 1), /proc may not be mounted yet. - if (IsMainThread() && !FileExists("/proc/self/maps")) { + if (IsMainThread() && + !MemoryMappingLayout::IsAvailable(/*cache_enabled*/ true)) { stack_top_ = stack_bottom_ = 0; tls_begin_ = tls_end_ = 0; } else { Index: compiler-rt/lib/sanitizer_common/sanitizer_flags.inc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_flags.inc +++ compiler-rt/lib/sanitizer_common/sanitizer_flags.inc @@ -243,3 +243,6 @@ COMMON_FLAG(bool, detect_write_exec, false, "If true, triggers warning when writable-executable pages requests " "are being made") +COMMON_FLAG(bool, test_only_emulate_no_procfs, false, + "TEST ONLY fail to open any files under /proc to emulate sanitized " + "\"init\"") Index: compiler-rt/lib/sanitizer_common/sanitizer_linux.h =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_linux.h +++ compiler-rt/lib/sanitizer_common/sanitizer_linux.h @@ -44,6 +44,7 @@ }; void ReadProcMaps(ProcSelfMapsBuff *proc_maps); +bool IsProcMapsAvailable(); // Syscall wrappers. uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count); Index: compiler-rt/lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_linux.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_linux.cc @@ -453,6 +453,8 @@ // ----------------- sanitizer_common.h bool FileExists(const char *filename) { + if (ShouldMockFailureToOpen(filename)) + return false; struct stat st; #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS if (internal_syscall(SYSCALL(newfstatat), AT_FDCWD, filename, &st, 0)) @@ -1003,6 +1005,8 @@ // Take care of unusable kernel area in top gigabyte. static uptr GetKernelAreaSize() { #if SANITIZER_LINUX && !SANITIZER_X32 + if (!MemoryMappingLayout::IsAvailable(/*cache_enabled*/ true)) + return 0; const uptr gbyte = 1UL << 30; // Firstly check if there are writable segments Index: compiler-rt/lib/sanitizer_common/sanitizer_mac.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_mac.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_mac.cc @@ -282,6 +282,8 @@ // ----------------- sanitizer_common.h bool FileExists(const char *filename) { + if (ShouldMockFailureToOpen(filename)) + return false; struct stat st; if (stat(filename, &st)) return false; Index: compiler-rt/lib/sanitizer_common/sanitizer_posix.h =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_posix.h +++ compiler-rt/lib/sanitizer_common/sanitizer_posix.h @@ -103,6 +103,8 @@ // Move the fd out of {0, 1, 2} range. fd_t ReserveStandardFds(fd_t fd); +bool ShouldMockFailureToOpen(const char *path); + } // namespace __sanitizer #endif // SANITIZER_POSIX_H Index: compiler-rt/lib/sanitizer_common/sanitizer_posix.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_posix.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_posix.cc @@ -18,6 +18,7 @@ #include "sanitizer_common.h" #include "sanitizer_file.h" +#include "sanitizer_flags.h" #include "sanitizer_libc.h" #include "sanitizer_posix.h" #include "sanitizer_procmaps.h" @@ -157,6 +158,8 @@ #endif fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) { + if (ShouldMockFailureToOpen(filename)) + return kInvalidFd; int flags; switch (mode) { case RdOnly: flags = O_RDONLY; break; @@ -229,6 +232,8 @@ // several worker threads on Mac, which aren't expected to map big chunks of // memory). bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { + if (!MemoryMappingLayout::IsAvailable(/*cache_enabled*/ true)) + return true; // hope for the best MemoryMappingLayout proc_maps(/*cache_enabled*/true); MemoryMappedSegment segment; while (proc_maps.Next(&segment)) { @@ -333,6 +338,11 @@ return fd; } +bool ShouldMockFailureToOpen(const char *path) { + return common_flags()->test_only_emulate_no_procfs && + internal_strncmp(path, "/proc/", 6) == 0; +} + } // namespace __sanitizer #endif // SANITIZER_POSIX Index: compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h +++ compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h @@ -75,6 +75,7 @@ // to obtain the memory mappings. It should fall back to pre-cached data // instead of aborting. static void CacheMemoryMappings(); + static bool IsAvailable(bool cache_enabled); // Adds all mapped objects into a vector. void DumpListOfModules(InternalMmapVectorNoCtor *modules); Index: compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cc @@ -45,6 +45,10 @@ namespace __sanitizer { +bool IsProcMapsAvailable() { + return true; +} + void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { const int Mib[] = { #if SANITIZER_FREEBSD Index: compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -144,6 +144,12 @@ } } +bool MemoryMappingLayout::IsAvailable(bool cache_enabled) { + if (cache_enabled && cached_proc_self_maps.data) + return true; + return IsProcMapsAvailable(); +} + void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { char *smaps = nullptr; uptr smaps_cap = 0; Index: compiler-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_procmaps_linux.cc @@ -13,10 +13,15 @@ #include "sanitizer_platform.h" #if SANITIZER_LINUX #include "sanitizer_common.h" +#include "sanitizer_file.h" #include "sanitizer_procmaps.h" namespace __sanitizer { +bool IsProcMapsAvailable() { + return FileExists("/proc/self/maps"); +} + void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { if (!ReadFileToBuffer("/proc/self/maps", &proc_maps->data, &proc_maps->mmaped_size, &proc_maps->len)) { Index: compiler-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cc @@ -20,6 +20,10 @@ namespace __sanitizer { +bool IsProcMapsAvailable() { + return FileExists("/proc/self/xmap"); +} + void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { ReadFileToBuffer("/proc/self/xmap", &proc_maps->data, &proc_maps->mmaped_size, &proc_maps->len); Index: compiler-rt/test/asan/TestCases/Posix/no-fd.cc =================================================================== --- compiler-rt/test/asan/TestCases/Posix/no-fd.cc +++ compiler-rt/test/asan/TestCases/Posix/no-fd.cc @@ -9,6 +9,10 @@ #include #include +extern "C" const char *__asan_default_options() { + return "test_only_emulate_no_procfs=1"; +} + void parent(int argc, char **argv) { fprintf(stderr, "hello\n"); // CHECK: hello