Index: lib/sanitizer_common/sanitizer_allocator_primary64.h =================================================================== --- lib/sanitizer_common/sanitizer_allocator_primary64.h +++ lib/sanitizer_common/sanitizer_allocator_primary64.h @@ -682,7 +682,7 @@ // Do it only when the feature is turned on, to avoid a potentially // extraneous syscall. if (ReleaseToOSIntervalMs() >= 0) - region->rtoi.last_release_at_ns = NanoTime(); + region->rtoi.last_release_at_ns = MonotonicNanoTime(); } // Do the mmap for the user memory. uptr map_size = kUserMapSize; @@ -819,7 +819,7 @@ return; if (region->rtoi.last_release_at_ns + interval_ms * 1000000ULL > - NanoTime()) { + MonotonicNanoTime()) { return; // Memory was returned recently. } } @@ -836,6 +836,6 @@ region->rtoi.num_releases += memory_mapper.GetReleasedRangesCount(); region->rtoi.last_released_bytes = memory_mapper.GetReleasedBytes(); } - region->rtoi.last_release_at_ns = NanoTime(); + region->rtoi.last_release_at_ns = MonotonicNanoTime(); } }; Index: lib/sanitizer_common/sanitizer_common.h =================================================================== --- lib/sanitizer_common/sanitizer_common.h +++ lib/sanitizer_common/sanitizer_common.h @@ -295,6 +295,7 @@ void SleepForSeconds(int seconds); void SleepForMillis(int millis); u64 NanoTime(); +u64 MonotonicNanoTime(); int Atexit(void (*function)(void)); void SortArray(uptr *array, uptr size); void SortArray(u32 *array, uptr size); Index: lib/sanitizer_common/sanitizer_common_interceptors.inc =================================================================== --- lib/sanitizer_common/sanitizer_common_interceptors.inc +++ lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -2005,6 +2005,13 @@ } return res; } +namespace __sanitizer { +extern "C" { +int real_clock_gettime(u32 clk_id, void *tp) { + return REAL(clock_gettime)(clk_id, tp); +} +} // extern "C" +} // namespace __sanitizer INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, clock_settime, clk_id, tp); Index: lib/sanitizer_common/sanitizer_fuchsia.cc =================================================================== --- lib/sanitizer_common/sanitizer_fuchsia.cc +++ lib/sanitizer_common/sanitizer_fuchsia.cc @@ -51,6 +51,8 @@ u64 NanoTime() { return _zx_time_get(ZX_CLOCK_UTC); } +u64 MonotonicNanoTime() { return _zx_time_get(ZX_CLOCK_MONOTONIC); } + uptr internal_getpid() { zx_info_handle_basic_t info; zx_status_t status = Index: lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux.cc +++ lib/sanitizer_common/sanitizer_linux.cc @@ -459,6 +459,40 @@ return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000; } +// glibc cannot use clock_gettime from a preinit_array function as the vDSO +// function pointers haven't been initialized yet. To prevent a crash, we check +// for the presence of the glibc symbol __vdso_clock_gettime, and verify that it +// is not null (it can be mangled so we can't use it directly). Bionic's +// clock_gettime actually falls back to the syscall in the same situation. +extern "C" SANITIZER_WEAK_ATTRIBUTE +int __vdso_clock_gettime(clockid_t clock, struct timespec* ts); +bool CanUseVDSO() { + return !SANITIZER_FREEBSD && !SANITIZER_NETBSD && + (SANITIZER_ANDROID || (&__vdso_clock_gettime && __vdso_clock_gettime)); +} + +// MonotonicNanoTime is a timing function that can leverage the vDSO by calling +// clock_gettime. real_clock_gettime only exists if clock_gettime is +// intercepted, so define it weakly and use it if available. +extern "C" SANITIZER_WEAK_ATTRIBUTE +int real_clock_gettime(u32 clk_id, void *tp); +u64 MonotonicNanoTime() { + timespec ts; + if (CanUseVDSO()) { + if (&real_clock_gettime) + real_clock_gettime(CLOCK_MONOTONIC, &ts); + else + clock_gettime(CLOCK_MONOTONIC, &ts); + } else { +#if SANITIZER_NETBSD + internal_syscall_ptr(SYSCALL(__clock_gettime50), CLOCK_MONOTONIC, &ts); +#else + internal_syscall_ptr(SYSCALL(clock_gettime), CLOCK_MONOTONIC, &ts); +#endif + } + return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec; +} + // Like getenv, but reads env directly from /proc (on Linux) or parses the // 'environ' array (on FreeBSD) and does not use libc. This function should be // called first inside __asan_init. Index: lib/sanitizer_common/sanitizer_win.cc =================================================================== --- lib/sanitizer_common/sanitizer_win.cc +++ lib/sanitizer_common/sanitizer_win.cc @@ -505,6 +505,10 @@ return 0; } +u64 MonotonicNanoTime() { + return 0; +} + void Abort() { internal__exit(3); } Index: lib/scudo/scudo_tsd.h =================================================================== --- lib/scudo/scudo_tsd.h +++ lib/scudo/scudo_tsd.h @@ -37,7 +37,7 @@ return true; } if (atomic_load_relaxed(&Precedence) == 0) - atomic_store_relaxed(&Precedence, NanoTime()); + atomic_store_relaxed(&Precedence, MonotonicNanoTime()); return false; }