| 1 | // Checks that we do not print a faraway buffer overrun if we find a |
| 2 | // use-after-free. |
| 3 | // RUN: %clang_hwasan -O0 %s -o %t |
| 4 | // RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK |
| 5 | |
| 6 | #include <sanitizer/hwasan_interface.h> |
| 7 | #include <stdio.h> |
| 8 | #include <stdlib.h> |
| 9 | |
| 10 | #define ALLOC_ATTEMPTS 256 |
| 11 | |
| 12 | char *Untag(void *x) { |
| 13 | return (char *)__hwasan_tag_pointer(p: x, tag: 0); |
| 14 | } |
| 15 | |
| 16 | void *FindMatch(void *ptrs[ALLOC_ATTEMPTS], void *value) { |
| 17 | for (int i = 0; i < ALLOC_ATTEMPTS; ++i) { |
| 18 | if (!ptrs[i]) |
| 19 | return NULL; |
| 20 | int distance = Untag(x: value) - Untag(x: ptrs[i]); |
| 21 | // Leave at least one granule of gap to the allocation. |
| 22 | if (abs(x: distance) < 1000 && abs(x: distance) > 32) |
| 23 | return ptrs[i]; |
| 24 | } |
| 25 | return NULL; |
| 26 | } |
| 27 | |
| 28 | int main(int argc, char **argv) { |
| 29 | __hwasan_enable_allocator_tagging(); |
| 30 | void *ptrs[ALLOC_ATTEMPTS] = {}; |
| 31 | // Find two allocations that are close enough so that they would be |
| 32 | // candidates as buffer overflows for each other. |
| 33 | void *one; |
| 34 | void *other; |
| 35 | for (int i = 0; i < ALLOC_ATTEMPTS; ++i) { |
| 36 | one = malloc(size: 16); |
| 37 | other = FindMatch(ptrs, value: one); |
| 38 | ptrs[i] = one; |
| 39 | if (other) |
| 40 | break; |
| 41 | } |
| 42 | if (!other) { |
| 43 | fprintf(stderr, format: "Could not find closeby allocations.\n" ); |
| 44 | abort(); |
| 45 | } |
| 46 | __hwasan_tag_memory(p: Untag(x: one), tag: 3, size: 16); |
| 47 | __hwasan_tag_memory(p: Untag(x: other), tag: 3, size: 16); |
| 48 | // Tag potential adjaceant allocations with a mismatching tag, otherwise this |
| 49 | // test would flake. |
| 50 | __hwasan_tag_memory(p: Untag(x: one) + 16, tag: 4, size: 16); |
| 51 | __hwasan_tag_memory(p: Untag(x: one) - 16, tag: 4, size: 16); |
| 52 | void *retagged_one = __hwasan_tag_pointer(p: one, tag: 3); |
| 53 | free(ptr: retagged_one); |
| 54 | volatile char *ptr = (char *)retagged_one; |
| 55 | *ptr = 1; |
| 56 | } |
| 57 | |
| 58 | // CHECK-NOT: Cause: heap-buffer-overflow |
| 59 | // CHECK: Cause: use-after-free |
| 60 | // CHECK-NOT: Cause: heap-buffer-overflow |
| 61 | |