Index: include/sanitizer/hwasan_interface.h =================================================================== --- include/sanitizer/hwasan_interface.h +++ include/sanitizer/hwasan_interface.h @@ -40,6 +40,13 @@ /// Set pointer tag. Previous tag is lost. void *__hwasan_tag_pointer(const volatile void *p, unsigned char tag); + // Set memory tag from the current SP address to the given address to zero. + // This is meant to annotate longjmp and other non-local jumps. + // This function needs to know the (almost) exact destination frame address; + // clearing shadow for the entire thread stack like __asan_handle_no_return + // does would cause false reports. + void __hwasan_handle_longjmp(const void *sp_dst); + // Print shadow and origin for the memory range to stderr in a human-readable // format. void __hwasan_print_shadow(const volatile void *x, size_t size); Index: lib/hwasan/hwasan.cc =================================================================== --- lib/hwasan/hwasan.cc +++ lib/hwasan/hwasan.cc @@ -409,6 +409,24 @@ return AddTagToPointer(p, tag); } +void __hwasan_handle_longjmp(const void *sp_dst) { + uptr dst = (uptr)sp_dst; + // HWASan does not support tagged SP. + CHECK(GetTagFromPointer(dst) == 0); + + uptr sp = (uptr)__builtin_frame_address(0); + static const uptr kMaxExpectedCleanupSize = 64 << 20; // 64M + if (dst < sp || dst - sp > kMaxExpectedCleanupSize) { + Report( + "WARNING: HWASan is ignoring requested __hwasan_handle_longjmp: " + "stack top: %p; target %p; distance: %p (%zd)\n" + "False positive error reports may follow\n", + (void *)sp, (void *)dst, dst - sp); + return; + } + TagMemory(sp, dst - sp, 0); +} + static const u8 kFallbackTag = 0xBB; u8 __hwasan_generate_tag() { Index: lib/hwasan/hwasan_interface_internal.h =================================================================== --- lib/hwasan/hwasan_interface_internal.h +++ lib/hwasan/hwasan_interface_internal.h @@ -111,6 +111,9 @@ void __hwasan_print_shadow(const void *x, uptr size); SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_handle_longjmp(const void *sp_dst); + +SANITIZER_INTERFACE_ATTRIBUTE u16 __sanitizer_unaligned_load16(const uu16 *p); SANITIZER_INTERFACE_ATTRIBUTE Index: test/hwasan/TestCases/longjmp.cc =================================================================== --- test/hwasan/TestCases/longjmp.cc +++ test/hwasan/TestCases/longjmp.cc @@ -0,0 +1,28 @@ +// RUN: %clangxx_hwasan -O0 -DNEGATIVE %s -o %t && %run %t 2>&1 +// RUN: %clangxx_hwasan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +// REQUIRES: stable-runtime + +#include +#include +#include + +__attribute__((noinline)) +int f(void *caller_frame) { + char z[32] = {}; + char *volatile p = z; + // Tag of local is never zero. + assert(__hwasan_tag_pointer(p, 0) != p); +#ifndef NEGATIVE + // This will destroy shadow of "z", and the following load will crash. + __hwasan_handle_longjmp(caller_frame); +#endif + return p[0]; +} + +int main() { + return f(__builtin_frame_address(0)); + // CHECK: READ of size 8 + // CHECK: pointer tag + // CHECK: memory tag 0x0 +}