[compiler-rt] [HWASan] [compiler-rt] Add tag_bits option to HWASan alloc (PR #192386)
Florian Mayer via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 15 21:28:16 PDT 2026
https://github.com/fmayer created https://github.com/llvm/llvm-project/pull/192386
This can be used to make sure the allocator does not use the top bit of
the pointer. This is useful when HWASan is used in combination with
signed-integer-overflow detection. Some code uses arithmetic on intptr_t
that overflows for sufficiently large pointers.
>From db3c8cd7ae44820b57ed10a1da5d7ef065d32f1e Mon Sep 17 00:00:00 2001
From: Florian Mayer <fmayer at google.com>
Date: Wed, 15 Apr 2026 21:28:01 -0700
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
=?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Created using spr 1.3.7
---
compiler-rt/lib/hwasan/hwasan_allocator.cpp | 16 ++++++++++++--
compiler-rt/lib/hwasan/hwasan_flags.inc | 2 ++
.../test/hwasan/TestCases/tag_mask_smoke.c | 21 +++++++++++++++++++
3 files changed, 37 insertions(+), 2 deletions(-)
create mode 100644 compiler-rt/test/hwasan/TestCases/tag_mask_smoke.c
diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp
index 75dbb336e3445..80cc8e1b69a23 100644
--- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp
@@ -46,6 +46,8 @@ enum {
// Initialized in HwasanAllocatorInit, an never changed.
alignas(16) static u8 tail_magic[kShadowAlignment - 1];
static uptr max_malloc_size;
+static unsigned hwasan_tag_bits;
+static tag_t fallback_alloc_tag;
bool HwasanChunkView::IsAllocated() const {
return metadata_ && metadata_->IsAllocated();
@@ -148,12 +150,22 @@ uptr GetAliasRegionStart() {
void HwasanAllocatorInit() {
atomic_store_relaxed(&hwasan_allocator_tagging_enabled,
!flags()->disable_allocator_tagging);
+ int flags_tag_bits = flags()->tag_bits;
+ if (flags_tag_bits < static_cast<int>(kTagBits) && flags_tag_bits > 0)
+ hwasan_tag_bits = flags_tag_bits;
+ else
+ hwasan_tag_bits = kTagBits;
+ // With flags_tag_bits we want to restrict the number of bits in the
+ // pointer. That's why we don't need to mask out the kFallbackFreeTag,
+ // because that one is only used for the memory tag, never the pointer
+ // tag.
+ fallback_alloc_tag = kFallbackAllocTag & ((1 << hwasan_tag_bits) - 1);
SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
allocator.InitLinkerInitialized(
common_flags()->allocator_release_to_os_interval_ms,
GetAliasRegionStart());
for (uptr i = 0; i < sizeof(tail_magic); i++)
- tail_magic[i] = GetCurrentThread()->GenerateRandomTag();
+ tail_magic[i] = GetCurrentThread()->GenerateRandomTag(hwasan_tag_bits);
if (common_flags()->max_allocation_size_mb) {
max_malloc_size = common_flags()->max_allocation_size_mb << 20;
max_malloc_size = Min(max_malloc_size, kMaxAllowedMallocSize);
@@ -237,7 +249,7 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
if (InTaggableRegion(reinterpret_cast<uptr>(user_ptr)) &&
atomic_load_relaxed(&hwasan_allocator_tagging_enabled) &&
flags()->tag_in_malloc && malloc_bisect(stack, orig_size)) {
- tag_t tag = t ? t->GenerateRandomTag() : kFallbackAllocTag;
+ tag_t tag = t ? t->GenerateRandomTag(hwasan_tag_bits) : fallback_alloc_tag;
uptr tag_size = orig_size ? orig_size : 1;
uptr full_granule_size = RoundDownTo(tag_size, kShadowAlignment);
user_ptr = (void *)TagMemoryAligned((uptr)user_ptr, full_granule_size, tag);
diff --git a/compiler-rt/lib/hwasan/hwasan_flags.inc b/compiler-rt/lib/hwasan/hwasan_flags.inc
index 058a0457b9e7f..b6903aad7dc85 100644
--- a/compiler-rt/lib/hwasan/hwasan_flags.inc
+++ b/compiler-rt/lib/hwasan/hwasan_flags.inc
@@ -91,3 +91,5 @@ HWASAN_FLAG(
"instead of choosing one dynamically."
"Tip: this can be combined with the compiler option, "
"-hwasan-mapping-offset, to optimize the instrumentation.")
+
+HWASAN_FLAG(int, tag_bits, 0, "Restrict number of bits to use for tags.")
diff --git a/compiler-rt/test/hwasan/TestCases/tag_mask_smoke.c b/compiler-rt/test/hwasan/TestCases/tag_mask_smoke.c
new file mode 100644
index 0000000000000..93e839c0ad9c2
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/tag_mask_smoke.c
@@ -0,0 +1,21 @@
+// RUN: %clang_hwasan -O0 %s -o %t
+// RUN: %env_hwasan_opts=tag_bits=7 %run %t 2>&1
+
+/// Running this once doesn't really prove anything, but it is a smoke test
+/// that we don't crash.
+
+#include <sanitizer/hwasan_interface.h>
+#include <stdlib.h>
+
+int main() {
+ __hwasan_enable_allocator_tagging();
+ // DUMP: [alloc] {{.*}} 10{{$}}
+ // DUMP: in main{{.*}}malloc_bisect.c
+ char *volatile p = (char *)malloc(10);
+ if (__hwasan_get_tag_from_pointer(p) & (1 << 7))
+ abort();
+ free(p);
+ __hwasan_disable_allocator_tagging();
+
+ return 0;
+}
More information about the llvm-commits
mailing list