[llvm] [BOLT] Keep instrumentation diagnostics out of line (PR #225986)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 18:20:10 PDT 2026


https://github.com/iliasabk created https://github.com/llvm/llvm-project/pull/225986

The instrumentation runtime's diagnostics reserve a 32 KiB scratch buffer on the stack. When `assert()` or `reportNumber()` get inlined into callers on instrumented code paths, the buffer inflates every caller frame — on small thread stacks a single such frame already overflows the guard region and the profiled binary segfaults even when no assertion fires.

Move the `assert()` failure path into a `noinline` helper (`reportAssertFailure`) and mark `reportNumber()` `noinline` as well, so the scratch buffer is only reserved when a diagnostic is actually emitted. This matches the fix sketched in the issue report.

Verified: `common.h` syntax-checks clean in the freestanding runtime build; the only behavioral change is where the buffer lives.

Fixes #225479


>From 1b8972ff52a4b9924e9ce55f8e8faaea78bd4858 Mon Sep 17 00:00:00 2001
From: iliasabk <iliasaberkane2908 at gmail.com>
Date: Wed, 23 Sep 2026 02:36:19 +0200
Subject: [PATCH] [BOLT] Keep instrumentation diagnostics out of line

The instrumentation runtime's report helpers each reserve a 32 KiB
scratch buffer on the stack. When assert() or reportNumber() are
inlined into callers on instrumented code paths, the buffer inflates
every caller frame and can overflow small thread stacks even when the
assertion never fires, crashing the profiled binary.

Move the assert() failure path into a noinline helper and mark
reportNumber() noinline as well.

Fixes #225479
---
 bolt/runtime/common.h | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/bolt/runtime/common.h b/bolt/runtime/common.h
index 36fb7c89dd7db..208c1feda4995 100644
--- a/bolt/runtime/common.h
+++ b/bolt/runtime/common.h
@@ -235,6 +235,10 @@ void *strStr(const char *const Haystack, const char *const Needle) {
   return nullptr;
 }
 
+// Diagnostic helpers allocate a large on-stack scratch buffer. Keep them
+// out of line: if inlined, the buffer is reserved in every caller frame and
+// can overflow small thread stacks even when the report is never emitted.
+__attribute__((noinline))
 void reportNumber(const char *Msg, uint64_t Num, uint32_t Base) {
 #if !defined(ANDROID_AARCH64)
   char Buf[BufSize];
@@ -326,9 +330,10 @@ void reportError(const char *Msg, uint64_t Size) {
 #endif
 }
 
-void assert(bool Assertion, const char *Msg) {
-  if (Assertion)
-    return;
+// Failure path of assert() kept out of line so its large on-stack buffer is
+// not reserved in every inlined caller frame (see reportNumber above).
+__attribute__((noinline))
+void reportAssertFailure(const char *Msg) {
 #if defined(ANDROID_AARCH64)
   (void)Msg;
   boltHandleFatalAndRecover();
@@ -342,6 +347,11 @@ void assert(bool Assertion, const char *Msg) {
 #endif
 }
 
+void assert(bool Assertion, const char *Msg) {
+  if (!Assertion)
+    reportAssertFailure(Msg);
+}
+
 #define SIG_BLOCK 0
 #define SIG_UNBLOCK 1
 #define SIG_SETMASK 2



More information about the llvm-commits mailing list