[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