[llvm] [llubi] Correctly render large addresses (PR #230845)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Sat Oct 10 13:55:23 PDT 2026


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/230845

>From d6d6b1a77110b8df4e75773a6162164305029e49 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 11 Oct 2026 03:51:59 +0800
Subject: [PATCH 1/3] [llubi] Correctly render large addresses in
 `verifyMemAccess`

---
 llvm/test/tools/llubi/wide_ptr_oob.ll | 15 +++++++++++++++
 llvm/tools/llubi/lib/ExecutorBase.cpp | 19 ++++++++++++-------
 2 files changed, 27 insertions(+), 7 deletions(-)
 create mode 100644 llvm/test/tools/llubi/wide_ptr_oob.ll

diff --git a/llvm/test/tools/llubi/wide_ptr_oob.ll b/llvm/test/tools/llubi/wide_ptr_oob.ll
new file mode 100644
index 0000000000000..42ccde4597b77
--- /dev/null
+++ b/llvm/test/tools/llubi/wide_ptr_oob.ll
@@ -0,0 +1,15 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
+
+target datalayout = "e-p:128:128"
+
+ at g = global i8 0
+define void @main() {
+  load i8, ptr getelementptr (i8, ptr @g, i128 18446744073709551616)
+  ret void
+}
+; CHECK: Entering function: main
+; CHECK-NEXT: Stacktrace:
+; CHECK-NEXT: #0   %1 = load i8, ptr getelementptr (i8, ptr @g, i128 18446744073709551616), align 1 at @main <stdin>:8
+; CHECK-NEXT: Immediate UB detected: Memory access is out of bounds. Accessed size: 1, Address: 0x10000000000000008, Object base: 0x8, Object size: 1.
+; CHECK-NEXT: error: Execution of function 'main' failed.
diff --git a/llvm/tools/llubi/lib/ExecutorBase.cpp b/llvm/tools/llubi/lib/ExecutorBase.cpp
index 0cbb38073f652..ede7c71f4e880 100644
--- a/llvm/tools/llubi/lib/ExecutorBase.cpp
+++ b/llvm/tools/llubi/lib/ExecutorBase.cpp
@@ -72,8 +72,10 @@ ExecutorBase::verifyMemAccess(const Pointer &Ptr, uint64_t AccessSize,
   // undefined behavior.
   if (IsStore ? MO->getState() != MemoryObjectState::Alive
               : MO->getState() == MemoryObjectState::Freed) {
+    SmallString<32> AddrStr;
+    Address.toStringUnsigned(AddrStr, 16);
     reportImmediateUB() << "Try to access a dead memory object at address 0x"
-                        << Twine::utohexstr(Address.getZExtValue()) << ".";
+                        << AddrStr << ".";
     return {};
   }
 
@@ -84,16 +86,18 @@ ExecutorBase::verifyMemAccess(const Pointer &Ptr, uint64_t AccessSize,
   }
 
   if (Address.countr_zero() < Log2(Alignment)) {
-    reportImmediateUB() << "Misaligned memory access. Address: 0x"
-                        << Twine::utohexstr(Address.getZExtValue())
+    SmallString<32> AddrStr;
+    Address.toStringUnsigned(AddrStr, 16);
+    reportImmediateUB() << "Misaligned memory access. Address: 0x" << AddrStr
                         << ", Required alignment: " << Alignment.value() << ".";
     return {};
   }
 
   if (AccessSize > MO->getSize() || Address.ult(MO->getAddress())) {
+    SmallString<32> AddrStr;
+    Address.toStringUnsigned(AddrStr, 16);
     reportImmediateUB() << "Memory access is out of bounds. Accessed size: "
-                        << AccessSize << ", Address: 0x"
-                        << Twine::utohexstr(Address.getZExtValue())
+                        << AccessSize << ", Address: 0x" << AddrStr
                         << ", Object base: 0x"
                         << Twine::utohexstr(MO->getAddress())
                         << ", Object size: " << MO->getSize() << ".";
@@ -103,9 +107,10 @@ ExecutorBase::verifyMemAccess(const Pointer &Ptr, uint64_t AccessSize,
   APInt Offset = Address - MO->getAddress();
 
   if (Offset.ugt(MO->getSize() - AccessSize)) {
+    SmallString<32> AddrStr;
+    Address.toStringUnsigned(AddrStr, 16);
     reportImmediateUB() << "Memory access is out of bounds. Accessed size: "
-                        << AccessSize << ", Address: 0x"
-                        << Twine::utohexstr(Address.getZExtValue())
+                        << AccessSize << ", Address: 0x" << AddrStr
                         << ", Object base: 0x"
                         << Twine::utohexstr(MO->getAddress())
                         << ", Object size: " << MO->getSize() << ".";

>From d53e98b3b70d34af7a73d14b3f9ed98abf1f29dd Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 11 Oct 2026 04:45:41 +0800
Subject: [PATCH 2/3] [llubi] Fix executeFree

---
 llvm/test/tools/llubi/wide_ptr_free.ll | 20 ++++++++++++++++++++
 llvm/tools/llubi/lib/Library.cpp       |  7 ++++---
 2 files changed, 24 insertions(+), 3 deletions(-)
 create mode 100644 llvm/test/tools/llubi/wide_ptr_free.ll

diff --git a/llvm/test/tools/llubi/wide_ptr_free.ll b/llvm/test/tools/llubi/wide_ptr_free.ll
new file mode 100644
index 0000000000000..97f008ae5e657
--- /dev/null
+++ b/llvm/test/tools/llubi/wide_ptr_free.ll
@@ -0,0 +1,20 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
+
+target datalayout = "p:128:128"
+
+declare void @free(ptr)
+
+define void @main() {
+  %a = alloca i8
+  %p = getelementptr i8, ptr %a, i128 18446744073709551616
+  call void @free(ptr %p)
+  ret void
+}
+; CHECK: Entering function: main
+; CHECK-NEXT:   %a = alloca i8, align 1 => ptr 0x8 [a]
+; CHECK-NEXT:   %p = getelementptr i8, ptr %a, i128 18446744073709551616 => ptr 0x10000000000000008 [a + 18446744073709551616]
+; CHECK-NEXT: Stacktrace:
+; CHECK-NEXT: #0   call void @free(ptr %p) at @main <stdin>:11
+; CHECK-NEXT: Immediate UB detected: freeing a pointer that does not point to the start of an allocation. Pointer address: 0x10000000000000008, allocation base: 0x8.
+; CHECK-NEXT: error: Execution of function 'main' failed.
diff --git a/llvm/tools/llubi/lib/Library.cpp b/llvm/tools/llubi/lib/Library.cpp
index 23c0ab04eecfa..38c02d5a829d7 100644
--- a/llvm/tools/llubi/lib/Library.cpp
+++ b/llvm/tools/llubi/lib/Library.cpp
@@ -133,12 +133,13 @@ AnyValue Library::executeFree(ArrayRef<AnyValue> Args, unsigned AS) {
     return AnyValue();
   }
 
-  if (const uint64_t Address = Ptr.address().getZExtValue();
-      Address != Obj->getAddress()) {
+  if (Ptr.address() != Obj->getAddress()) {
+    SmallString<32> AddrStr;
+    Ptr.address().toStringUnsigned(AddrStr, 16);
     Executor.reportImmediateUB()
         << "freeing a pointer that does not point to "
            "the start of an allocation. Pointer address: 0x"
-        << Twine::utohexstr(Address) << ", allocation base: 0x"
+        << AddrStr << ", allocation base: 0x"
         << Twine::utohexstr(Obj->getAddress()) << ".";
     return AnyValue();
   }

>From 21dfe9ecd473f1f98db17dd8986c4fb3f276ea3c Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 11 Oct 2026 04:53:57 +0800
Subject: [PATCH 3/3] [llubi] Use `Obj->getAddress()`

---
 llvm/tools/llubi/lib/Library.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/llvm/tools/llubi/lib/Library.cpp b/llvm/tools/llubi/lib/Library.cpp
index 38c02d5a829d7..51f5dfd4a2e46 100644
--- a/llvm/tools/llubi/lib/Library.cpp
+++ b/llvm/tools/llubi/lib/Library.cpp
@@ -162,9 +162,8 @@ AnyValue Library::executeFree(ArrayRef<AnyValue> Args, unsigned AS) {
   // function comes from a different family (C++ delete, etc.)
 
   if (!Ctx.free(*Obj)) {
-    Executor.reportImmediateUB()
-        << "freeing an invalid pointer at 0x"
-        << Twine::utohexstr(Ptr.address().getZExtValue()) << ".";
+    Executor.reportImmediateUB() << "freeing an invalid pointer at 0x"
+                                 << Twine::utohexstr(Obj->getAddress()) << ".";
     return AnyValue::poison();
   }
 



More information about the llvm-commits mailing list