https://github.com/boomanaiden154 created 
https://github.com/llvm/llvm-project/pull/186133

0e314ef4a6e779df813f408da23dd15f636eec74 updated the fuzz tests to ensure that 
they call SBDebugger::Terminate() on shutdown. However, this ended up causing 
msan failures. Initializing the static variable on the first fuzz test ends up 
causing use after destroys as timers are stored in a thread_local static 
variable in LLDB. This ends up getting destroyed earlier (by virtue of being 
thread_local) than the SBDebuggerContextManager.

So we move initialization back into LLVMFuzzerInitialize to ensure that timers 
are initialized before SBDebuggerContextManager is (which will ensure they are 
destroyed later) and make SBDebuggerContextManager thread_local to ensure the 
correct destruction order.

I couldn't find any issues calling SBDebugger::Terminate() multiple times, but 
that doesn't seem right and it's trivial to make the context manager ref 
counting.

This does make the code a bit messier and harder to understand, but seems like 
the simplest way to get everything working given there doesn't seem to be any 
LLVMFuzzerCleanup method or anything.

>From bd06872781ae291ab7864663f557d9307ac5869d Mon Sep 17 00:00:00 2001
From: Aiden Grossman <[email protected]>
Date: Thu, 12 Mar 2026 14:48:51 +0000
Subject: [PATCH] [LLDB] Fix Timer MSAN Use After Destroy in Fuzz Tests

0e314ef4a6e779df813f408da23dd15f636eec74 updated the fuzz tests to
ensure that they call SBDebugger::Terminate() on shutdown. However, this
ended up causing msan failures. Initializing the static variable on the
first fuzz test ends up causing use after destroys as timers are stored
in a thread_local static variable in LLDB. This ends up getting
destroyed earlier (by virtue of being thread_local) than the
SBDebuggerContextManager.

So we move initialization back into LLVMFuzzerInitialize to ensure that
timers are initialized before SBDebuggerContextManager is (which will
ensure they are destroyed later) and make SBDebuggerContextManager
thread_local to ensure the correct destruction order.

I couldn't find any issues calling SBDebugger::Terminate() multiple
times, but that doesn't seem right and it's trivial to make the context
manager ref counting.

This does make the code a bit messier and harder to understand, but
seems like the simplest way to get everything working given there
doesn't seem to be any LLVMFuzzerCleanup method or anything.
---
 .../lldb-commandinterpreter-fuzzer.cpp                 |  8 +++++++-
 .../lldb-target-fuzzer/lldb-target-fuzzer.cpp          |  8 +++++++-
 .../tools/lldb-fuzzer/utils/SBDebuggerContextManager.h | 10 ++++++++--
 3 files changed, 22 insertions(+), 4 deletions(-)

diff --git 
a/lldb/tools/lldb-fuzzer/lldb-commandinterpreter-fuzzer/lldb-commandinterpreter-fuzzer.cpp
 
b/lldb/tools/lldb-fuzzer/lldb-commandinterpreter-fuzzer/lldb-commandinterpreter-fuzzer.cpp
index 60f7d5458b234..3317265aae638 100644
--- 
a/lldb/tools/lldb-fuzzer/lldb-commandinterpreter-fuzzer/lldb-commandinterpreter-fuzzer.cpp
+++ 
b/lldb/tools/lldb-fuzzer/lldb-commandinterpreter-fuzzer/lldb-commandinterpreter-fuzzer.cpp
@@ -19,8 +19,14 @@
 using namespace lldb;
 using namespace lldb_fuzzer;
 
+extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
+  SBDebugger::Initialize();
+  return 0;
+}
+
 extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
-  static SBDebuggerContextManager ctx_manager = SBDebuggerContextManager();
+  static thread_local SBDebuggerContextManager ctx_manager =
+      SBDebuggerContextManager();
 
   // Convert the data into a null-terminated string
   std::string str((char *)data, size);
diff --git a/lldb/tools/lldb-fuzzer/lldb-target-fuzzer/lldb-target-fuzzer.cpp 
b/lldb/tools/lldb-fuzzer/lldb-target-fuzzer/lldb-target-fuzzer.cpp
index 6b8ea1f361398..ff2000b0f0b6d 100644
--- a/lldb/tools/lldb-fuzzer/lldb-target-fuzzer/lldb-target-fuzzer.cpp
+++ b/lldb/tools/lldb-fuzzer/lldb-target-fuzzer/lldb-target-fuzzer.cpp
@@ -16,8 +16,14 @@ using namespace lldb;
 using namespace lldb_fuzzer;
 using namespace llvm;
 
+extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
+  SBDebugger::Initialize();
+  return 0;
+}
+
 extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
-  static SBDebuggerContextManager ctx_manager = SBDebuggerContextManager();
+  static thread_local SBDebuggerContextManager ctx_manager =
+      SBDebuggerContextManager();
 
   std::unique_ptr<TempFile> file = TempFile::Create(data, size);
   if (!file)
diff --git a/lldb/tools/lldb-fuzzer/utils/SBDebuggerContextManager.h 
b/lldb/tools/lldb-fuzzer/utils/SBDebuggerContextManager.h
index ecc1e2dfa74d9..c7de7e595c796 100644
--- a/lldb/tools/lldb-fuzzer/utils/SBDebuggerContextManager.h
+++ b/lldb/tools/lldb-fuzzer/utils/SBDebuggerContextManager.h
@@ -13,10 +13,16 @@ using namespace lldb;
 namespace lldb_fuzzer {
 
 class SBDebuggerContextManager {
+  inline static int instance_count;
+
 public:
-  SBDebuggerContextManager() { SBDebugger::Initialize(); }
+  SBDebuggerContextManager() { ++instance_count; }
 
-  ~SBDebuggerContextManager() { SBDebugger::Terminate(); }
+  ~SBDebuggerContextManager() {
+    --instance_count;
+    if (instance_count == 0)
+      SBDebugger::Terminate();
+  }
 };
 
 } // namespace lldb_fuzzer

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to