Index: compiler-rt/trunk/lib/hwasan/hwasan.cc =================================================================== --- compiler-rt/trunk/lib/hwasan/hwasan.cc +++ compiler-rt/trunk/lib/hwasan/hwasan.cc @@ -336,14 +336,14 @@ if (sz == 0) return -1; tag_t ptr_tag = GetTagFromPointer((uptr)p); - if (ptr_tag == 0) - return -1; uptr ptr_raw = UntagAddr(reinterpret_cast(p)); uptr shadow_first = MemToShadow(ptr_raw); uptr shadow_last = MemToShadow(ptr_raw + sz - 1); for (uptr s = shadow_first; s <= shadow_last; ++s) - if (*(tag_t*)s != ptr_tag) - return ShadowToMem(s) - ptr_raw; + if (*(tag_t *)s != ptr_tag) { + sptr offset = ShadowToMem(s) - ptr_raw; + return offset < 0 ? 0 : offset; + } return -1; } Index: compiler-rt/trunk/lib/hwasan/hwasan_checks.h =================================================================== --- compiler-rt/trunk/lib/hwasan/hwasan_checks.h +++ compiler-rt/trunk/lib/hwasan/hwasan_checks.h @@ -14,6 +14,7 @@ #define HWASAN_CHECKS_H #include "hwasan_mapping.h" +#include "sanitizer_common/sanitizer_common.h" namespace __hwasan { template @@ -22,8 +23,8 @@ (void)p; // 0x900 is added to do not interfere with the kernel use of lower values of // brk immediate. - // FIXME: Add a constraint to put the pointer into x0, the same as x86 branch. - asm("brk %0\n\t" ::"n"(0x900 + X)); + register uptr x0 asm("x0") = p; + asm("brk %1\n\t" ::"r"(x0), "n"(0x900 + X)); #elif defined(__x86_64__) // INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes // total. The pointer is passed via rdi. @@ -41,6 +42,25 @@ // __builtin_unreachable(); } +// Version with access size which is not power of 2 +template +__attribute__((always_inline)) static void SigTrap(uptr p, uptr size) { +#if defined(__aarch64__) + register uptr x0 asm("x0") = p; + register uptr x1 asm("x1") = size; + asm("brk %2\n\t" ::"r"(x0), "r"(x1), "n"(0x900 + X)); +#elif defined(__x86_64__) + // Size is stored in rsi. + asm volatile( + "int3\n" + "nopl %c0(%%rax)\n" ::"n"(0x40 + X), + "D"(p), "S"(size)); +#else + __builtin_trap(); +#endif + // __builtin_unreachable(); +} + enum class ErrorAction { Abort, Recover }; enum class AccessType { Load, Store }; @@ -69,7 +89,7 @@ for (tag_t *t = shadow_first; t <= shadow_last; ++t) if (UNLIKELY(ptr_tag != *t)) { SigTrap<0x20 * (EA == ErrorAction::Recover) + - 0x10 * (AT == AccessType::Store) + 0xf>(p); + 0x10 * (AT == AccessType::Store) + 0xf>(p, sz); if (EA == ErrorAction::Abort) __builtin_unreachable(); } Index: compiler-rt/trunk/lib/hwasan/hwasan_report.cc =================================================================== --- compiler-rt/trunk/lib/hwasan/hwasan_report.cc +++ compiler-rt/trunk/lib/hwasan/hwasan_report.cc @@ -399,13 +399,21 @@ Thread *t = GetCurrentThread(); + sptr offset = + __hwasan_test_shadow(reinterpret_cast(tagged_addr), access_size); + CHECK(offset >= 0 && offset < static_cast(access_size)); tag_t ptr_tag = GetTagFromPointer(tagged_addr); - tag_t *tag_ptr = reinterpret_cast(MemToShadow(untagged_addr)); + tag_t *tag_ptr = + reinterpret_cast(MemToShadow(untagged_addr + offset)); tag_t mem_tag = *tag_ptr; + Printf("%s", d.Access()); Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem) in thread T%zd\n", is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag, mem_tag, t->unique_id()); + if (offset != 0) + Printf("Invalid access starting at offset [%zu, %zu)\n", offset, + Min(access_size, static_cast(offset) + (1 << kShadowScale))); Printf("%s", d.Default()); stack->Print(); Index: compiler-rt/trunk/test/hwasan/TestCases/mem-intrinsics.c =================================================================== --- compiler-rt/trunk/test/hwasan/TestCases/mem-intrinsics.c +++ compiler-rt/trunk/test/hwasan/TestCases/mem-intrinsics.c @@ -10,8 +10,8 @@ #include int main() { - char Q[16]; - char P[16]; + char Q[16] __attribute__((aligned(256))); + char P[16] __attribute__((aligned(256))); #if TEST_NO == 1 memset(Q, 0, 32); #elif TEST_NO == 2 @@ -21,15 +21,17 @@ #endif write(STDOUT_FILENO, "recovered\n", 10); // WRITE: ERROR: HWAddressSanitizer: tag-mismatch on address - // WRITE: WRITE {{.*}} tags: [[PTR_TAG:..]]/[[MEM_TAG:..]] (ptr/mem) + // WRITE: WRITE of size 32 at {{.*}} tags: [[PTR_TAG:..]]/[[MEM_TAG:..]] (ptr/mem) + // WRITE: Invalid access starting at offset [16, 32) // WRITE: Memory tags around the buggy address (one tag corresponds to 16 bytes): - // WRITE: =>{{.*}}[[MEM_TAG]] + // WRITE: =>{{.*}}[[PTR_TAG]]{{[[:space:]]\[}}[[MEM_TAG]] // WRITE-NOT: recovered // READ: ERROR: HWAddressSanitizer: tag-mismatch on address + // READ-NOT: Invalid access starting at offset // READ: READ {{.*}} tags: [[PTR_TAG:..]]/[[MEM_TAG:..]] (ptr/mem) // READ: Memory tags around the buggy address (one tag corresponds to 16 bytes): - // READ: =>{{.*}}[[MEM_TAG]] + // READ: =>{{.*}}[[PTR_TAG]]{{[[:space:]]\[}}[[MEM_TAG]] // READ-NOT: recovered // RECOVER: recovered