https://github.com/GeorgeHuyubo created 
https://github.com/llvm/llvm-project/pull/175700

When displaying a backtrace with std::tuple function arguments, 
GetChildAtIndex() can return a null ValueObjectSP. The code was dereferencing 
this pointer without checking for null, causing a SIGSEGV crash when LLDB tried 
to pretty-print function arguments containing tuples.

Example lldb crash bt:
```
(lldb) bt
LLDB diagnostics will be written to /tmp/diagnostics-02b2ba
Please include the directory content when filing a bug report
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and 
include the crash backtrace.
Stack dump:
0.      Program arguments: ./build/Debug/fbcode-x86_64/toolchain/bin/lldb -o 
"auto-load-debuginfo 
/mnt/persistent-public/alexandreperez/tdiye4de13zax4j9/tdiye4de13zax4j9"
 #0 0x000055c3e8be3d25 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) 
/home/hyubo/llvm-sand/external/llvm-project/llvm/lib/Support/Unix/Signals.inc:848:11
 #1 0x000055c3e8be44f4 PrintStackTraceSignalHandler(void*) 
/home/hyubo/llvm-sand/external/llvm-project/llvm/lib/Support/Unix/Signals.inc:931:1
 #2 0x000055c3e8be18f9 llvm::sys::RunSignalHandlers() 
/home/hyubo/llvm-sand/external/llvm-project/llvm/lib/Support/Signals.cpp:104:5
 #3 0x000055c3e8be602b SignalHandler(int, siginfo_t*, void*) 
/home/hyubo/llvm-sand/external/llvm-project/llvm/lib/Support/Unix/Signals.inc:430:38
 #4 0x00007f162f044560 __restore_rt 
/home/engshare/third-party2/glibc/2.34/src/glibc-2.34/signal/../sysdeps/unix/sysv/linux/libc_sigaction.c:13:0
 #5 0x00007f162f125649 syscall 
/home/engshare/third-party2/glibc/2.34/src/glibc-2.34/misc/../sysdeps/unix/sysv/linux/x86_64/syscall.S:38:0
 #6 0x00007f163584a6c0 SignalHandler(int, siginfo_t*, void*) 
/home/hyubo/llvm-sand/external/llvm-project/llvm/lib/Support/Unix/Signals.inc:429:7
 #7 0x00007f162f044560 __restore_rt 
/home/engshare/third-party2/glibc/2.34/src/glibc-2.34/signal/../sysdeps/unix/sysv/linux/libc_sigaction.c:13:0
 #8 0x00007f16347f182a lldb_private::ValueObject::GetName() const 
/home/hyubo/llvm-sand/external/llvm-project/lldb/include/lldb/ValueObject/ValueObject.h:487:40
 #9 0x00007f16351a9f95 (anonymous 
namespace)::LibStdcppTupleSyntheticFrontEnd::Update() 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp:69:44
#10 0x00007f16351a9bfe (anonymous 
namespace)::LibStdcppTupleSyntheticFrontEnd::LibStdcppTupleSyntheticFrontEnd(std::shared_ptr<lldb_private::ValueObject>)
 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp:52:1
#11 0x00007f16351a9b62 
lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator(lldb_private::CXXSyntheticChildren*,
 std::shared_ptr<lldb_private::ValueObject>) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp:112:27
#12 0x00007f1635148d9e 
GenericTupleSyntheticFrontEndCreator(lldb_private::CXXSyntheticChildren*, 
std::shared_ptr<lldb_private::ValueObject>) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp:1556:3
#13 0x00007f163514618b lldb_private::SyntheticChildrenFrontEnd* 
std::__invoke_impl<lldb_private::SyntheticChildrenFrontEnd*, 
lldb_private::SyntheticChildrenFrontEnd* 
(*&)(lldb_private::CXXSyntheticChildren*, 
std::shared_ptr<lldb_private::ValueObject>), 
lldb_private::CXXSyntheticChildren*, 
std::shared_ptr<lldb_private::ValueObject>>(std::__invoke_other, 
lldb_private::SyntheticChildrenFrontEnd* 
(*&)(lldb_private::CXXSyntheticChildren*, 
std::shared_ptr<lldb_private::ValueObject>), 
lldb_private::CXXSyntheticChildren*&&, 
std::shared_ptr<lldb_private::ValueObject>&&) 
/mnt/gvfs/third-party2/libgcc/d1129753c8361ac8e9453c0f4291337a4507ebe6/11.x/platform010/5684a5a/include/c++/11.x/bits/invoke.h:61:14
#14 0x00007f1635146107 
std::enable_if<is_invocable_r_v<lldb_private::SyntheticChildrenFrontEnd*, 
lldb_private::SyntheticChildrenFrontEnd* 
(*&)(lldb_private::CXXSyntheticChildren*, 
std::shared_ptr<lldb_private::ValueObject>), 
lldb_private::CXXSyntheticChildren*, 
std::shared_ptr<lldb_private::ValueObject>>, 
lldb_private::SyntheticChildrenFrontEnd*>::type 
std::__invoke_r<lldb_private::SyntheticChildrenFrontEnd*, 
lldb_private::SyntheticChildrenFrontEnd* 
(*&)(lldb_private::CXXSyntheticChildren*, 
std::shared_ptr<lldb_private::ValueObject>), 
lldb_private::CXXSyntheticChildren*, 
std::shared_ptr<lldb_private::ValueObject>>(lldb_private::SyntheticChildrenFrontEnd*
 (*&)(lldb_private::CXXSyntheticChildren*, 
std::shared_ptr<lldb_private::ValueObject>), 
lldb_private::CXXSyntheticChildren*&&, 
std::shared_ptr<lldb_private::ValueObject>&&) 
/mnt/gvfs/third-party2/libgcc/d1129753c8361ac8e9453c0f4291337a4507ebe6/11.x/platform010/5684a5a/include/c++/11.x/bits/invoke.h:114:2
#15 0x00007f163514603d 
std::_Function_handler<lldb_private::SyntheticChildrenFrontEnd* 
(lldb_private::CXXSyntheticChildren*, 
std::shared_ptr<lldb_private::ValueObject>), 
lldb_private::SyntheticChildrenFrontEnd* 
(*)(lldb_private::CXXSyntheticChildren*, 
std::shared_ptr<lldb_private::ValueObject>)>::_M_invoke(std::_Any_data const&, 
lldb_private::CXXSyntheticChildren*&&, 
std::shared_ptr<lldb_private::ValueObject>&&) 
/mnt/gvfs/third-party2/libgcc/d1129753c8361ac8e9453c0f4291337a4507ebe6/11.x/platform010/5684a5a/include/c++/11.x/bits/std_function.h:291:2
#16 0x00007f1634af8245 std::function<lldb_private::SyntheticChildrenFrontEnd* 
(lldb_private::CXXSyntheticChildren*, 
std::shared_ptr<lldb_private::ValueObject>)>::operator()(lldb_private::CXXSyntheticChildren*,
 std::shared_ptr<lldb_private::ValueObject>) const 
/mnt/gvfs/third-party2/libgcc/d1129753c8361ac8e9453c0f4291337a4507ebe6/11.x/platform010/5684a5a/include/c++/11.x/bits/std_function.h:560:2
#17 0x00007f1634af7b84 
lldb_private::CXXSyntheticChildren::GetFrontEnd(lldb_private::ValueObject&) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/include/lldb/DataFormatters/TypeSynthetic.h:392:9
#18 0x00007f1634efbda3 lldb_private::ValueObjectSynthetic::CreateSynthFilter() 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/ValueObject/ValueObjectSynthetic.cpp:155:36
#19 0x00007f1634efb3c1 
lldb_private::ValueObjectSynthetic::ValueObjectSynthetic(lldb_private::ValueObject&,
 std::shared_ptr<lldb_private::SyntheticChildren>) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/ValueObject/ValueObjectSynthetic.cpp:66:1
#20 0x00007f1634ee1d62 lldb_private::ValueObject::CalculateSyntheticValue() 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/ValueObject/ValueObject.cpp:2038:27
#21 0x00007f1634edb61d lldb_private::ValueObject::GetSyntheticValue() 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/ValueObject/ValueObject.cpp:2069:3
#22 0x00007f1634ee4823 
lldb_private::ValueObject::GetQualifiedRepresentationIfAvailable(lldb::DynamicValueType,
 bool) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/ValueObject/ValueObject.cpp:2784:36
#23 0x00007f16349fd384 
lldb_private::FormatEntity::PrettyPrintFunctionArguments(lldb_private::Stream&, 
lldb_private::VariableList const&, lldb_private::ExecutionContextScope*) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Core/FormatEntity.cpp:2629:22
#24 0x00007f163513a555 
lldb_private::CPlusPlusLanguage::HandleFrameFormatVariable(lldb_private::SymbolContext
 const&, lldb_private::ExecutionContext const*, 
lldb_private::FormatEntity::Entry::Type, lldb_private::Stream&) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp:2271:5
#25 0x00007f16349f8005 
lldb_private::FormatEntity::Format(lldb_private::FormatEntity::Entry const&, 
lldb_private::Stream&, lldb_private::SymbolContext const*, 
lldb_private::ExecutionContext const*, lldb_private::Address const*, 
lldb_private::ValueObject*, bool, bool) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Core/FormatEntity.cpp:1877:5
#26 0x00007f16349f5cd7 
lldb_private::FormatEntity::Format(lldb_private::FormatEntity::Entry const&, 
lldb_private::Stream&, lldb_private::SymbolContext const*, 
lldb_private::ExecutionContext const*, lldb_private::Address const*, 
lldb_private::ValueObject*, bool, bool) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Core/FormatEntity.cpp:1344:11
#27 0x00007f16349fba58 FormatFunctionNameForLanguage(lldb_private::Stream&, 
lldb_private::ExecutionContext const*, lldb_private::SymbolContext const*) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Core/FormatEntity.cpp:1293:14
#28 0x00007f16349f8048 
lldb_private::FormatEntity::Format(lldb_private::FormatEntity::Entry const&, 
lldb_private::Stream&, lldb_private::SymbolContext const*, 
lldb_private::ExecutionContext const*, lldb_private::Address const*, 
lldb_private::ValueObject*, bool, bool) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Core/FormatEntity.cpp:1885:9
#29 0x00007f16349f8c6f 
lldb_private::FormatEntity::Format(lldb_private::FormatEntity::Entry const&, 
lldb_private::Stream&, lldb_private::SymbolContext const*, 
lldb_private::ExecutionContext const*, lldb_private::Address const*, 
lldb_private::ValueObject*, bool, 
bool)::$_0::operator()(std::vector<lldb_private::FormatEntity::Entry, 
std::allocator<lldb_private::FormatEntity::Entry>> const&) const 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Core/FormatEntity.cpp:1360:13
#30 0x00007f16349f5e50 
lldb_private::FormatEntity::Format(lldb_private::FormatEntity::Entry const&, 
lldb_private::Stream&, lldb_private::SymbolContext const*, 
lldb_private::ExecutionContext const*, lldb_private::Address const*, 
lldb_private::ValueObject*, bool, bool) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Core/FormatEntity.cpp:1368:11
#31 0x00007f16349f8c6f 
lldb_private::FormatEntity::Format(lldb_private::FormatEntity::Entry const&, 
lldb_private::Stream&, lldb_private::SymbolContext const*, 
lldb_private::ExecutionContext const*, lldb_private::Address const*, 
lldb_private::ValueObject*, bool, 
bool)::$_0::operator()(std::vector<lldb_private::FormatEntity::Entry, 
std::allocator<lldb_private::FormatEntity::Entry>> const&) const 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Core/FormatEntity.cpp:1360:13
#32 0x00007f16349f5e50 
lldb_private::FormatEntity::Format(lldb_private::FormatEntity::Entry const&, 
lldb_private::Stream&, lldb_private::SymbolContext const*, 
lldb_private::ExecutionContext const*, lldb_private::Address const*, 
lldb_private::ValueObject*, bool, bool) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Core/FormatEntity.cpp:1368:11
#33 0x00007f16349f5cd7 
lldb_private::FormatEntity::Format(lldb_private::FormatEntity::Entry const&, 
lldb_private::Stream&, lldb_private::SymbolContext const*, 
lldb_private::ExecutionContext const*, lldb_private::Address const*, 
lldb_private::ValueObject*, bool, bool) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Core/FormatEntity.cpp:1344:11
#34 0x00007f1634d62853 
lldb_private::StackFrame::DumpUsingFormat(lldb_private::Stream&, 
lldb_private::FormatEntity::Entry const*, llvm::StringRef) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Target/StackFrame.cpp:1929:14
#35 0x00007f1634d62a92 
lldb_private::StackFrame::DumpUsingSettingsFormat(lldb_private::Stream*, bool, 
char const*) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Target/StackFrame.cpp:1956:7
#36 0x00007f1634d632d5 
lldb_private::StackFrame::GetStatus(lldb_private::Stream&, bool, bool, bool, 
char const*) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Target/StackFrame.cpp:2043:7
#37 0x00007f1634d6b2a7 
lldb_private::StackFrameList::GetStatus(lldb_private::Stream&, unsigned int, 
unsigned int, bool, unsigned int, bool, bool, char const*) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Target/StackFrameList.cpp:937:9
#38 0x00007f1634ded778 lldb_private::Thread::GetStatus(lldb_private::Stream&, 
unsigned int, unsigned int, unsigned int, bool, bool, bool) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Target/Thread.cpp:1827:22
#39 0x00007f16372041dd CommandObjectThreadBacktrace::HandleOneThread(unsigned 
long, lldb_private::CommandReturnObject&) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Commands/CommandObjectThread.cpp:239:10
#40 0x00007f163721e9e1 
lldb_private::CommandObjectIterateOverThreads::DoExecute(lldb_private::Args&, 
lldb_private::CommandReturnObject&) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.cpp:46:5
#41 0x00007f1634bb984c lldb_private::CommandObjectParsed::Execute(char const*, 
lldb_private::CommandReturnObject&) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Interpreter/CommandObject.cpp:832:5
#42 0x00007f1634b89e70 lldb_private::CommandInterpreter::HandleCommand(char 
const*, lldb_private::LazyBool, lldb_private::CommandReturnObject&, bool) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp:2211:3
#43 0x00007f16371bfefd 
lldb_private::CommandObjectRegexCommand::DoExecute(llvm::StringRef, 
lldb_private::CommandReturnObject&) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Commands/CommandObjectRegexCommand.cpp:76:21
#44 0x00007f1634bb9b6f lldb_private::CommandObjectRaw::Execute(char const*, 
lldb_private::CommandReturnObject&) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Interpreter/CommandObject.cpp:0:7
#45 0x00007f1634b89e70 lldb_private::CommandInterpreter::HandleCommand(char 
const*, lldb_private::LazyBool, lldb_private::CommandReturnObject&, bool) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp:2211:3
#46 0x00007f1634b8f0d1 
lldb_private::CommandInterpreter::IOHandlerInputComplete(lldb_private::IOHandler&,
 std::__cxx11::basic_string<char, std::char_traits<char>, 
std::allocator<char>>&) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp:3331:15
#47 0x00007f1634a072e4 lldb_private::IOHandlerEditline::Run() 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Core/IOHandler.cpp:605:7
#48 0x00007f16349b3dec lldb_private::Debugger::RunIOHandlers() 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Core/Debugger.cpp:1280:16
#49 0x00007f1634b90b4f 
lldb_private::CommandInterpreter::RunCommandInterpreter(lldb_private::CommandInterpreterRunOptions&)
 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp:3620:16
#50 0x00007f16346f2e09 lldb::SBDebugger::RunCommandInterpreter(bool, bool) 
/home/hyubo/llvm-sand/external/llvm-project/lldb/source/API/SBDebugger.cpp:1234:42
#51 0x000055c3e8b63770 Driver::MainLoop() 
/home/hyubo/llvm-sand/external/llvm-project/lldb/tools/driver/Driver.cpp:677:3
#52 0x000055c3e8b642e6 main 
/home/hyubo/llvm-sand/external/llvm-project/lldb/tools/driver/Driver.cpp:887:17
#53 0x00007f162f02c657 __libc_start_call_main 
/home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#54 0x00007f162f02c718 call_init 
/home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../csu/libc-start.c:128:20
#55 0x00007f162f02c718 __libc_start_main@GLIBC_2.2.5 
/home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../csu/libc-start.c:379:5
#56 0x000055c3e8b5fad1 _start 
/home/engshare/third-party2/glibc/2.34/src/glibc-2.34/csu/../sysdeps/x86_64/start.S:118:0
Segmentation fault (core dumped)
```

This PR fix the crash and add unit test which would crash before this PR and 
only pass after this PR.

>From c7d1acc30240d55164543730b43f17df8fc98108 Mon Sep 17 00:00:00 2001
From: George Hu <[email protected]>
Date: Mon, 12 Jan 2026 18:29:23 -0800
Subject: [PATCH] [lldb] Fix null pointer crash in
 LibStdcppTupleSyntheticFrontEnd::Update

---
 .../Language/CPlusPlus/LibStdcppTuple.cpp     |   2 +
 .../Language/CPlusPlus/CMakeLists.txt         |   4 +
 .../Language/CPlusPlus/LibStdcppTupleTest.cpp | 167 ++++++++++++++++++
 3 files changed, 173 insertions(+)
 create mode 100644 lldb/unittests/Language/CPlusPlus/LibStdcppTupleTest.cpp

diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
index cf72265bfbad3..076bbbb87448d 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
@@ -66,6 +66,8 @@ lldb::ChildCacheState 
LibStdcppTupleSyntheticFrontEnd::Update() {
     size_t child_count = current_child->GetNumChildrenIgnoringErrors();
     for (size_t i = 0; i < child_count; ++i) {
       ValueObjectSP child_sp = current_child->GetChildAtIndex(i);
+      if (!child_sp)
+        continue;
       llvm::StringRef name_str = child_sp->GetName().GetStringRef();
       if (name_str.starts_with("std::_Tuple_impl<")) {
         next_child_sp = child_sp;
diff --git a/lldb/unittests/Language/CPlusPlus/CMakeLists.txt 
b/lldb/unittests/Language/CPlusPlus/CMakeLists.txt
index 1d96fcf3db1b8..e680b5db77904 100644
--- a/lldb/unittests/Language/CPlusPlus/CMakeLists.txt
+++ b/lldb/unittests/Language/CPlusPlus/CMakeLists.txt
@@ -1,7 +1,11 @@
 add_lldb_unittest(LanguageCPlusPlusTests
   CPlusPlusLanguageTest.cpp
+  LibStdcppTupleTest.cpp
 
   LINK_LIBS
+    lldbCore
+    lldbHost
     lldbPluginCPlusPlusLanguage
+    lldbPluginTypeSystemClang
     LLVMTestingSupport
   )
diff --git a/lldb/unittests/Language/CPlusPlus/LibStdcppTupleTest.cpp 
b/lldb/unittests/Language/CPlusPlus/LibStdcppTupleTest.cpp
new file mode 100644
index 0000000000000..e85592fb13c7e
--- /dev/null
+++ b/lldb/unittests/Language/CPlusPlus/LibStdcppTupleTest.cpp
@@ -0,0 +1,167 @@
+//===-- LibStdcppTupleTest.cpp 
--------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Language/CPlusPlus/LibStdcpp.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "TestingSupport/SubsystemRAII.h"
+#include "TestingSupport/Symbol/ClangTestUtils.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/ValueObject/ValueObject.h"
+
+#include "gtest/gtest.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+/// A minimal ValueObject mock that returns null from GetChildAtIndex for a
+/// specified index. This simulates the crash scenario where GetChildAtIndex()
+/// returns null due to incomplete debug info or type system errors.
+class ValueObjectWithNullChild : public ValueObject {
+public:
+  static lldb::ValueObjectSP Create(CompilerType type, ConstString name,
+                                    size_t null_child_idx) {
+    auto manager = ValueObjectManager::Create();
+    auto *obj =
+        new ValueObjectWithNullChild(*manager, type, name, null_child_idx);
+    return obj->GetSP();
+  }
+
+  ~ValueObjectWithNullChild() override = default;
+
+  llvm::Expected<uint64_t> GetByteSize() override { return 4; }
+
+  lldb::ValueType GetValueType() const override {
+    return lldb::eValueTypeConstResult;
+  }
+
+  llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override {
+    auto num_or_err = m_type.GetNumChildren(true, nullptr);
+    if (!num_or_err)
+      return num_or_err.takeError();
+    return *num_or_err;
+  }
+
+  ConstString GetTypeName() override { return m_type.GetTypeName(); }
+
+  ConstString GetDisplayTypeName() override { return GetTypeName(); }
+
+  bool IsInScope() override { return true; }
+
+protected:
+  bool UpdateValue() override {
+    m_error.Clear();
+    return true;
+  }
+
+  CompilerType GetCompilerTypeImpl() override { return m_type; }
+
+  /// This is the key method - return null for the specified child index
+  /// to simulate the crash scenario.
+  ValueObject *CreateChildAtIndex(size_t idx) override {
+    if (idx == m_null_child_idx) {
+      return nullptr; // Return null to trigger the crash scenario!
+    }
+    return ValueObject::CreateChildAtIndex(idx);
+  }
+
+private:
+  ValueObjectWithNullChild(ValueObjectManager &manager, CompilerType type,
+                           ConstString name, size_t null_child_idx)
+      : ValueObject(nullptr, manager), m_type(type),
+        m_null_child_idx(null_child_idx) {
+    SetName(name);
+  }
+
+  CompilerType m_type;
+  size_t m_null_child_idx;
+};
+
+class LibStdcppTupleTest : public ::testing::Test {
+public:
+  SubsystemRAII<FileSystem, HostInfo> m_subsystems;
+
+  void SetUp() override {
+    m_holder = std::make_unique<clang_utils::TypeSystemClangHolder>("test");
+    m_type_system = m_holder->GetAST();
+  }
+
+  /// Create a struct type with a child named "std::_Tuple_impl<0, int>"
+  /// to trigger the tuple synthetic frontend's child iteration.
+  CompilerType CreateTypeWithTupleImplChild() {
+    // Create outer type
+    CompilerType outer_type = m_type_system->CreateRecordType(
+        m_type_system->getASTContext().getTranslationUnitDecl(),
+        OptionalClangModuleID(), lldb::AccessType::eAccessPublic,
+        "std::tuple<int>", 0, lldb::LanguageType::eLanguageTypeC_plus_plus);
+
+    // Create inner _Tuple_impl type
+    CompilerType inner_type = m_type_system->CreateRecordType(
+        m_type_system->getASTContext().getTranslationUnitDecl(),
+        OptionalClangModuleID(), lldb::AccessType::eAccessPublic,
+        "std::_Tuple_impl<0, int>", 0,
+        lldb::LanguageType::eLanguageTypeC_plus_plus);
+
+    TypeSystemClang::StartTagDeclarationDefinition(inner_type);
+    TypeSystemClang::CompleteTagDeclarationDefinition(inner_type);
+
+    // Add the inner type as a field of the outer type
+    TypeSystemClang::StartTagDeclarationDefinition(outer_type);
+    m_type_system->AddFieldToRecordType(
+        outer_type, "std::_Tuple_impl<0, int>", inner_type,
+        lldb::AccessType::eAccessPublic, 0);
+    TypeSystemClang::CompleteTagDeclarationDefinition(outer_type);
+
+    return outer_type;
+  }
+
+  TypeSystemClang *m_type_system;
+
+private:
+  std::unique_ptr<clang_utils::TypeSystemClangHolder> m_holder;
+};
+
+} // anonymous namespace
+
+TEST_F(LibStdcppTupleTest, CreatorHandlesNullValueObject) {
+  auto *frontend = formatters::LibStdcppTupleSyntheticFrontEndCreator(
+      nullptr, lldb::ValueObjectSP());
+  EXPECT_EQ(frontend, nullptr);
+}
+
+/// This test verifies the null child handling fix.
+/// It creates a ValueObject that returns null from GetChildAtIndex(0),
+/// simulating the crash scenario from incomplete debug info.
+/// WITHOUT the fix (null check), this test will crash with SIGSEGV.
+/// WITH the fix, this test passes.
+TEST_F(LibStdcppTupleTest, UpdateHandlesNullChild) {
+  CompilerType type = CreateTypeWithTupleImplChild();
+
+  // Create a ValueObject that returns null for child at index 0
+  auto valobj_sp = ValueObjectWithNullChild::Create(
+      type, ConstString("test_tuple"), 0 /* null_child_idx */);
+  ASSERT_TRUE(valobj_sp);
+
+  // Verify our mock returns null for child 0
+  ASSERT_FALSE(valobj_sp->GetChildAtIndex(0));
+
+  // Create the frontend - this calls Update() which iterates through children.
+  // WITHOUT the null check fix, this crashes with SIGSEGV when trying to call
+  // GetName() on a null child_sp.
+  // WITH the fix, this succeeds because null children are skipped.
+  auto *frontend =
+      formatters::LibStdcppTupleSyntheticFrontEndCreator(nullptr, valobj_sp);
+  ASSERT_NE(frontend, nullptr);
+
+  // If we get here, the null check worked
+  auto num_children = frontend->CalculateNumChildren();
+  ASSERT_TRUE(static_cast<bool>(num_children));
+
+  delete frontend;
+}

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

Reply via email to