Index: compiler-rt/include/sanitizer/common_interface_defs.h =================================================================== --- compiler-rt/include/sanitizer/common_interface_defs.h +++ compiler-rt/include/sanitizer/common_interface_defs.h @@ -341,6 +341,30 @@ const void **bottom_old, size_t *size_old); +/// Calls the user-provided callback for each Fake stack region for the +/// specified thread ID. +/// +/// \param os_tid Thread ID. Only the Fake stack of this thread ID is considered. +/// \param callback User-provided callback. For each stack region, +/// callback is called with begin and +/// end marking the stack span and arg +/// equal to the arg parameter value passed. +/// \param arg This value is passed as last parameter to callback. +void __sanitizer_for_each_extra_stack_range( + uint64_t os_tid, void (*callback)(size_t begin, size_t end, void *arg), + void *arg); + +/// Calls the user-provided callback for each Fake stack region for +/// threads that have a Fake stack. +/// +/// \param callback User-provided callback. For each stack region, +/// callback is called with begin and +/// end marking the stack span and arg +/// equal to the user-provided arg value. +/// \param arg This value is passed as last parameter to callback. +void __sanitizer_for_each_extra_stack_range_all_threads( + void (*callback)(size_t begin, size_t end, void *arg), void *arg); + // Get full module name and calculate pc offset within it. // Returns 1 if pc belongs to some module, 0 if module was not found. int __sanitizer_get_module_and_offset_for_pc(void *pc, char *module_path, Index: compiler-rt/lib/asan/asan_interface.inc =================================================================== --- compiler-rt/lib/asan/asan_interface.inc +++ compiler-rt/lib/asan/asan_interface.inc @@ -154,6 +154,8 @@ INTERFACE_FUNCTION(__asan_unregister_image_globals) INTERFACE_FUNCTION(__asan_version_mismatch_check_v8) INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber) +INTERFACE_FUNCTION(__sanitizer_for_each_extra_stack_range) +INTERFACE_FUNCTION(__sanitizer_for_each_extra_stack_range_all_threads) INTERFACE_FUNCTION(__sanitizer_print_stack_trace) INTERFACE_FUNCTION(__sanitizer_ptr_cmp) INTERFACE_FUNCTION(__sanitizer_ptr_sub) Index: compiler-rt/lib/asan/asan_thread.cpp =================================================================== --- compiler-rt/lib/asan/asan_thread.cpp +++ compiler-rt/lib/asan/asan_thread.cpp @@ -533,4 +533,40 @@ (uptr*)bottom_old, (uptr*)size_old); } + +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_for_each_extra_stack_range( + u64 os_id, void (*callback)(uptr begin, uptr end, void *arg), void *arg) { + AsanThread *t = GetAsanThreadByOsIDLocked(os_id); + if (t && t->has_fake_stack()) + t->fake_stack()->ForEachFakeFrame(callback, arg); +} + +struct RichRangeIteratorCallback { + RangeIteratorCallback callback; + void *arg; +}; + +static void +CallRichRangeCallback(ThreadContextBase *tctx_base, void *arg) { + auto *cb = reinterpret_cast(arg); + auto *tctx = static_cast(tctx_base); + AsanThread *t = tctx->thread; + if (t && t->has_fake_stack()) + t->fake_stack()->ForEachFakeFrame(cb->callback, cb->arg); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_for_each_extra_stack_range_all_threads( + void (*callback)(uptr begin, uptr end, void *arg), void *arg) { + if (!__asan_option_detect_stack_use_after_return) + return; + + RichRangeIteratorCallback cb = {callback, arg}; + { + ThreadRegistryLock l(&asanThreadRegistry()); + asanThreadRegistry().RunCallbackForEachThreadLocked(CallRichRangeCallback, + &cb); + } } +} // extern "C"