[Lldb-commits] [lldb] Ensure that the Synthetic children of a ValueObject are managed by their parents ClusterManager (PR #192561)

via lldb-commits lldb-commits at lists.llvm.org
Thu Apr 16 15:47:05 PDT 2026


https://github.com/jimingham created https://github.com/llvm/llvm-project/pull/192561

A very common pattern in our synthetic child providers was to make the child ValueObject using ValueObjectConstResult::Create or some form of the static ValueObject::CreateValueObjectFrom*** methods, and store and hand that out as the child.  Doing that creates a "root" ValueObject whose lifecycle is not linked to the lifecycle of the ValueObject it is a child of.  And that means it is possible that either the child or the parent could have gotten destroyed when the other ValueObject gets asked a question about it.

For the most part this doesn't happen because there are usually enough other shared pointer references binding the two to keep both sides alive.  But we have gotten a small but steady stream of reports for years now of crashes where a ValueObject accesses its ClusterManager but that has already been deleted.  I've never been able to find a reproducible case of this, but one plausible cause is that we are violating the contract that "all the children of a ValueObject have coterminous lifespans, enforced by the ClusterManager".  So it is unsurprising that they might sometimes not stay alive as long as they should.

This patch addresses that by providing a way to use these static create methods but passing in the ClusterManager to be used, and adds or modifies where extant the CreateChildValueObjectFrom*** methods to pass in the parent manager.

This patch is not complete.  It turns out that routing the ClusterManager from CreateValueObjectFromExpression all the way to where the expression result VO is made is quite intrusive, and would have made this already quite large (though largly mechanical) patch become unweildy.  Since I am mostly concerned about synthetic child providers, and we discourage using expressions for them, I think that's an acceptable separation.

I also added a test where the ValueObjectSynthetic hands out its children, checking whether the child being handed out is in fact owned by the parent handing it out.  It is controlled by a setting (target.check-vo-ownership) which is currently off by default - since I can't provide a way to do this correctly for expressions yet.  But I turn it on in the testsuite.  That's the real testing strategy for this patch, since its goal is to ensure that all the children we hand out are managed by their parents.  I didn't put an equivalent check in ValueObjectVariable because that system really doesn't allow a way to do this incorrectly.

I also fixed some of the tests that were making children using CreateValueObjectFromExpression to make their children with CreateValueObjectFromData instead.  I could have opted the tests out of the check, but using the expression parser to do this work is not best practice, so I didn't want to leave bad examples around. I left one case that does do it with expressions, however, so we still have a test for that not-recommended but people do it anyway path.

>From 3210e4734b92f114e6334526ebf7c7157c7da3d6 Mon Sep 17 00:00:00 2001
From: Jim Ingham <jingham at apple.com>
Date: Fri, 3 Apr 2026 13:51:28 -0700
Subject: [PATCH] A very common pattern in our synthetic child providers was to
 make the child ValueObject using ValueObjectConstResult::Create or some form
 of the static ValueObject::CreateValueObjectFrom*** methods, and store and
 hand that out as the child.  Doing that creates a "root" ValueObject whose
 lifecycle is not linked to the lifecycle of the ValueObject it is a child of.
  And that means it is possible that either the child or the parent could have
 gotten destroyed when the other ValueObject gets asked a question about it.

For the most part this doesn't happen because there are usually
enough other shared pointer references binding the two to keep both
sides alive.  But we have gotten a small but steady stream of reports
for years now of crashes where a ValueObject accesses its ClusterManager
but that has already been deleted.  I've never been able to find a
reproducible case of this, but one plausible cause is that we are violating
the contract that "all the children of a ValueObject have coterminous
lifespans, enforced by the ClusterManager".  So it is unsurprising that
they might sometimes not stay alive as long as they should.

This patch addresses that by providing a way to use these static
create methods but passing in the ClusterManager to be used, and adds
or modifies where extant the CreateChildValueObjectFrom*** methods to
pass in the parent manager.

This patch is not complete.  It turns out that routing the
ClusterManager from CreateValueObjectFromExpression all the way to
where the expression result VO is made is quite intrusive, and would
have made this already quite large (though largly mechanical) patch
become unweildy.  Since I am mostly concerned about synthetic child
providers, and we discourage using expressions for them, I think that's
an acceptable separation.

I also added a test where the ValueObjectSynthetic hands out its
children, checking whether the child being handed out is in fact
owned by the parent handing it out.  It is controlled by a setting
(target.check-vo-ownership) which is currently off by default - since
I can't provide a way to do this correctly for expressions yet.  But
I turn it on in the testsuite.  That's the real testing strategy for
this patch, since its goal is to ensure that all the children we hand
out are managed by their parents.  I didn't put an equivalent check
in ValueObjectVariable because that system really doesn't allow a
way to do this incorrectly.

I also fixed some of the tests that were making children using
CreateValueObjectFromExpression to make their children with
CreateValueObjectFromData instead.  I could have opted the tests out
of the check, but using the expression parser to do this work is
not best practice, so I didn't want to leave bad examples around.
I left one case that does do it with expressions, however, so we still have
a test for that not-recommended but people do it anyway path.
---
 .../lldb/DataFormatters/TypeSynthetic.h       |   6 +-
 lldb/include/lldb/Target/Target.h             |   4 +
 lldb/include/lldb/ValueObject/ValueObject.h   | 104 ++++++++++++++++--
 .../lldb/ValueObject/ValueObjectConstResult.h |  21 ++--
 .../Python/lldbsuite/test/lldbtest.py         |   1 +
 lldb/source/API/SBValue.cpp                   |   8 +-
 lldb/source/DataFormatters/TypeSynthetic.cpp  |  19 ++--
 .../Plugins/Language/CPlusPlus/Coroutines.cpp |   8 +-
 .../Language/CPlusPlus/GenericBitset.cpp      |   2 +-
 .../CPlusPlus/GenericInitializerList.cpp      |   2 +-
 .../Language/CPlusPlus/GenericList.cpp        |  10 +-
 .../Language/CPlusPlus/LibCxxProxyArray.cpp   |   4 +-
 .../Language/CPlusPlus/LibCxxSliceArray.cpp   |   2 +-
 .../Plugins/Language/CPlusPlus/LibCxxSpan.cpp |   2 +-
 .../Language/CPlusPlus/LibCxxUnorderedMap.cpp |   2 +-
 .../Language/CPlusPlus/LibCxxValarray.cpp     |   2 +-
 .../Language/CPlusPlus/LibCxxVector.cpp       |   6 +-
 .../Plugins/Language/CPlusPlus/LibStdcpp.cpp  |   4 +-
 .../Language/CPlusPlus/LibStdcppSpan.cpp      |   2 +-
 .../Language/CPlusPlus/MsvcStlDeque.cpp       |   2 +-
 .../Language/CPlusPlus/MsvcStlSpan.cpp        |   2 +-
 .../Language/CPlusPlus/MsvcStlVector.cpp      |   6 +-
 lldb/source/Plugins/Language/ObjC/NSArray.cpp |   4 +-
 .../Plugins/Language/ObjC/NSDictionary.cpp    |  12 +-
 lldb/source/Plugins/Language/ObjC/NSError.cpp |   2 +-
 .../Plugins/Language/ObjC/NSException.cpp     |  61 ++++++----
 .../Plugins/Language/ObjC/NSIndexPath.cpp     |  25 ++---
 lldb/source/Plugins/Language/ObjC/NSSet.cpp   |   6 +-
 .../source/Plugins/Language/ObjC/NSString.cpp |   2 +-
 lldb/source/Target/Target.cpp                 |  11 ++
 lldb/source/Target/TargetProperties.td        |   3 +
 lldb/source/ValueObject/ValueObject.cpp       |  70 +++++++++---
 .../ValueObject/ValueObjectConstResult.cpp    |  78 +++++++++----
 .../ValueObjectConstResultImpl.cpp            |   2 +-
 .../ValueObject/ValueObjectSynthetic.cpp      |   7 +-
 .../expression/issue_11588/Test11588.py       |   4 +-
 .../TestDataFormatterCallbackMatching.py      |   1 +
 .../data-formatter-python-synth/ftsp.py       |   6 +-
 .../type-synth-wants-deref/provider.py        |   6 +-
 lldb/test/API/python_api/formatters/synth.py  |   5 +-
 40 files changed, 370 insertions(+), 154 deletions(-)

diff --git a/lldb/include/lldb/DataFormatters/TypeSynthetic.h b/lldb/include/lldb/DataFormatters/TypeSynthetic.h
index 7bcf12f334fde..c2348e03b34b8 100644
--- a/lldb/include/lldb/DataFormatters/TypeSynthetic.h
+++ b/lldb/include/lldb/DataFormatters/TypeSynthetic.h
@@ -88,16 +88,16 @@ class SyntheticChildrenFrontEnd {
 
 protected:
   lldb::ValueObjectSP
-  CreateValueObjectFromExpression(llvm::StringRef name,
+  CreateChildValueObjectFromExpression(llvm::StringRef name,
                                   llvm::StringRef expression,
                                   const ExecutionContext &exe_ctx);
 
   lldb::ValueObjectSP
-  CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address,
+  CreateChildValueObjectFromAddress(llvm::StringRef name, uint64_t address,
                                const ExecutionContext &exe_ctx,
                                CompilerType type, bool do_deref = true);
 
-  lldb::ValueObjectSP CreateValueObjectFromData(llvm::StringRef name,
+  lldb::ValueObjectSP CreateChildValueObjectFromData(llvm::StringRef name,
                                                 const DataExtractor &data,
                                                 const ExecutionContext &exe_ctx,
                                                 CompilerType type);
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index 67f373aa5a325..8fdf5bbdd89ae 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -284,6 +284,10 @@ class TargetProperties : public Properties {
   void SetDebugUtilityExpression(bool debug);
 
   bool GetDebugUtilityExpression() const;
+  
+  void SetCheckValueObjectOwnership(bool check);
+  
+  bool GetCheckValueObjectOwnership() const;
 
   std::optional<LoadScriptFromSymFile>
   GetAutoLoadScriptsForModule(llvm::StringRef module_name) const;
diff --git a/lldb/include/lldb/ValueObject/ValueObject.h b/lldb/include/lldb/ValueObject/ValueObject.h
index cf69a713f1366..d9e63ff380605 100644
--- a/lldb/include/lldb/ValueObject/ValueObject.h
+++ b/lldb/include/lldb/ValueObject/ValueObject.h
@@ -705,16 +705,25 @@ class ValueObject {
 
   llvm::Error Dump(Stream &s, const DumpValueObjectOptions &options);
 
+  /// The following static routines create "Root" ValueObjects if parent is
+  /// null.  If it is a valid ValueObject, the new ValueObject is managed by the
+  /// ValueObjectManager of the parent object.
+  /// However, if you are creating a ValueObject in a Synthetic Child Provider,
+  /// use the method CreateChildValueObjectFrom... instead for that purpose.
+  /// That will ensure the right parent is passed in.
+
   static lldb::ValueObjectSP
   CreateValueObjectFromExpression(llvm::StringRef name,
                                   llvm::StringRef expression,
-                                  const ExecutionContext &exe_ctx);
+                                  const ExecutionContext &exe_ctx,
+                                  ValueObject *parent = nullptr);
 
   static lldb::ValueObjectSP
   CreateValueObjectFromExpression(llvm::StringRef name,
                                   llvm::StringRef expression,
                                   const ExecutionContext &exe_ctx,
-                                  const EvaluateExpressionOptions &options);
+                                  const EvaluateExpressionOptions &options,
+                                  ValueObject *parent = nullptr);
 
   /// Given an address either create a value object containing the value at
   /// that address, or create a value object containing the address itself
@@ -723,40 +732,113 @@ class ValueObject {
   static lldb::ValueObjectSP
   CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address,
                                const ExecutionContext &exe_ctx,
-                               CompilerType type, bool do_deref = true);
+                               CompilerType type, bool do_deref = true,
+                               ValueObject *parent = nullptr);
 
   static lldb::ValueObjectSP
   CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data,
-                            const ExecutionContext &exe_ctx, CompilerType type);
+                            const ExecutionContext &exe_ctx, CompilerType type,
+                                  ValueObject *parent = nullptr);
 
   /// Create a value object containing the given APInt value.
   static lldb::ValueObjectSP
   CreateValueObjectFromAPInt(const ExecutionContext &exe_ctx,
                              const llvm::APInt &v, CompilerType type,
-                             llvm::StringRef name);
+                             llvm::StringRef name,
+                             ValueObject *parent = nullptr);
 
   /// Create a value object containing the given APFloat value.
   static lldb::ValueObjectSP
   CreateValueObjectFromAPFloat(const ExecutionContext &exe_ctx,
                                const llvm::APFloat &v, CompilerType type,
-                               llvm::StringRef name);
+                               llvm::StringRef name,
+                               ValueObject *parent = nullptr);
 
   /// Create a value object containing the given Scalar value.
   static lldb::ValueObjectSP
   CreateValueObjectFromScalar(const ExecutionContext &exe_ctx, Scalar &s,
-                              CompilerType type, llvm::StringRef name);
+                              CompilerType type, llvm::StringRef name,
+                              ValueObject *parent = nullptr);
 
   /// Create a value object containing the given boolean value.
   static lldb::ValueObjectSP
   CreateValueObjectFromBool(const ExecutionContext &exe_ctx,
                             lldb::TypeSystemSP typesystem, bool value,
-                            llvm::StringRef name);
+                            llvm::StringRef name,
+                            ValueObject *parent = nullptr);
 
   /// Create a nullptr value object with the specified type (must be a
   /// nullptr type).
   static lldb::ValueObjectSP
   CreateValueObjectFromNullptr(const ExecutionContext &exe_ctx,
-                               CompilerType type, llvm::StringRef name);
+                               CompilerType type, llvm::StringRef name,
+                               ValueObject *parent = nullptr);
+
+  /// These are the appropriate routines to make a ValueObject that get managed
+  /// by this ValueObject (and all the other members of its Cluster).
+  lldb::ValueObjectSP
+  CreateChildValueObjectFromExpression(llvm::StringRef name,
+                                  llvm::StringRef expression,
+                                  const ExecutionContext &exe_ctx,
+                                  const EvaluateExpressionOptions &options) {
+    return CreateValueObjectFromExpression(name, expression, exe_ctx, options, this);
+  }
+
+  /// Given an address either create a value object containing the value at
+  /// that address, or create a value object containing the address itself
+  /// (pointer value), depending on whether the parameter 'do_deref' is true or
+  /// false.
+  lldb::ValueObjectSP
+  CreateChildValueObjectFromAddress(llvm::StringRef name, uint64_t address,
+                               const ExecutionContext &exe_ctx,
+                               CompilerType type, bool do_deref = true)  {
+    return CreateValueObjectFromAddress(name, address, exe_ctx, type, do_deref, this);
+  }
+
+  lldb::ValueObjectSP
+  CreateChildValueObjectFromData(llvm::StringRef name, const DataExtractor &data,
+                            const ExecutionContext &exe_ctx, CompilerType type)  {
+    return CreateValueObjectFromData(name, data, exe_ctx, type, this);
+  }
+
+  /// Create a value object containing the given APInt value.
+  lldb::ValueObjectSP
+  CreateChildValueObjectFromAPInt(const ExecutionContext &exe_ctx,
+                             const llvm::APInt &v, CompilerType type,
+                             llvm::StringRef name)  {
+    return CreateValueObjectFromAPInt(exe_ctx, v, type, name, this);
+  }
+
+  /// Create a value object containing the given APFloat value.
+  lldb::ValueObjectSP
+  CreateChildValueObjectFromAPFloat(const ExecutionContext &exe_ctx,
+                               const llvm::APFloat &v, CompilerType type,
+                               llvm::StringRef name)  {
+    return CreateValueObjectFromAPFloat(exe_ctx, v, type, name, this);
+  }
+
+  /// Create a value object containing the given Scalar value.
+  lldb::ValueObjectSP
+  CreateChildValueObjectFromScalar(const ExecutionContext &exe_ctx, Scalar &s,
+                              CompilerType type, llvm::StringRef name)  {
+    return CreateValueObjectFromScalar(exe_ctx, s, type, name, this);
+  }
+
+  /// Create a value object containing the given boolean value.
+  lldb::ValueObjectSP
+  CreateChildValueObjectFromBool(const ExecutionContext &exe_ctx,
+                            lldb::TypeSystemSP typesystem, bool value,
+                            llvm::StringRef name)  {                             
+    return CreateValueObjectFromBool(exe_ctx, typesystem, value, name, this);
+  }
+
+  /// Create a nullptr value object with the specified type (must be a
+  /// nullptr type).
+  lldb::ValueObjectSP
+  CreateChildValueObjectFromNullptr(const ExecutionContext &exe_ctx,
+                               CompilerType type, llvm::StringRef name)  {
+    return CreateValueObjectFromNullptr(exe_ctx, type, name, this);
+  }
 
   lldb::ValueObjectSP Persist();
 
@@ -891,6 +973,8 @@ class ValueObject {
   /// pointing to, and thus also can't know its size. See the comment in
   /// Value::m_value for a more thorough explanation of why that is.
   llvm::ArrayRef<uint8_t> GetLocalBuffer() const;
+  
+  lldb::ValueObjectSP CheckValueObjectOwnership(ValueObject *child);
 
 protected:
   typedef ClusterManager<ValueObject> ValueObjectManager;
@@ -935,7 +1019,7 @@ class ValueObject {
     ChildrenMap m_children;
     size_t m_children_count = 0;
   };
-
+  
   // Classes that inherit from ValueObject can see and modify these
 
   /// The parent value object, or nullptr if this has no parent.
diff --git a/lldb/include/lldb/ValueObject/ValueObjectConstResult.h b/lldb/include/lldb/ValueObject/ValueObjectConstResult.h
index 6fbb15328ee5c..1ddea2bc8b832 100644
--- a/lldb/include/lldb/ValueObject/ValueObjectConstResult.h
+++ b/lldb/include/lldb/ValueObject/ValueObjectConstResult.h
@@ -37,37 +37,44 @@ class ValueObjectConstResult : public ValueObject {
 
   static lldb::ValueObjectSP
   Create(ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order,
-         uint32_t addr_byte_size, lldb::addr_t address = LLDB_INVALID_ADDRESS);
+         uint32_t addr_byte_size, lldb::addr_t address = LLDB_INVALID_ADDRESS,
+         ValueObjectManager *manager = nullptr);
 
   static lldb::ValueObjectSP
   Create(ExecutionContextScope *exe_scope, const CompilerType &compiler_type,
          ConstString name, const DataExtractor &data,
-         lldb::addr_t address = LLDB_INVALID_ADDRESS);
+         lldb::addr_t address = LLDB_INVALID_ADDRESS,
+         ValueObjectManager *manager = nullptr);
 
   static lldb::ValueObjectSP
   Create(ExecutionContextScope *exe_scope, const CompilerType &compiler_type,
          ConstString name, const lldb::DataBufferSP &result_data_sp,
          lldb::ByteOrder byte_order, uint32_t addr_size,
-         lldb::addr_t address = LLDB_INVALID_ADDRESS);
+         lldb::addr_t address = LLDB_INVALID_ADDRESS,
+         ValueObjectManager *manager = nullptr);
 
   static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope,
                                     const CompilerType &compiler_type,
                                     ConstString name, lldb::addr_t address,
                                     AddressType address_type,
-                                    uint32_t addr_byte_size);
+                                    uint32_t addr_byte_size,
+                                    ValueObjectManager *manager = nullptr);
 
   static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope,
                                     Value &value, ConstString name,
-                                    Module *module = nullptr);
+                                    Module *module = nullptr,
+                                    ValueObjectManager *manager = nullptr);
 
   static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope,
                                     const CompilerType &compiler_type,
                                     Scalar &scalar, ConstString name,
-                                    Module *module = nullptr);
+                                    Module *module = nullptr,
+                                    ValueObjectManager *manager = nullptr);
 
   // When an expression fails to evaluate, we return an error
   static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope,
-                                    Status &&error);
+                                    Status &&error,
+                                    ValueObjectManager *manager = nullptr);
 
   llvm::Expected<uint64_t> GetByteSize() override;
 
diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index f2a9f3bba1993..aacde8265c9f4 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -818,6 +818,7 @@ def setUpCommands(cls):
             "settings set use-color false",
             # Disable the statusline by default.
             "settings set show-statusline false",
+            "settings set target.check-vo-ownership true",
         ]
 
         # Set any user-overridden settings.
diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index a27da7b61f8ea..8fbcecb493721 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -434,7 +434,7 @@ lldb::SBValue SBValue::CreateValueFromExpression(const char *name,
   lldb::ValueObjectSP new_value_sp;
   if (value_sp) {
     ExecutionContext exe_ctx(value_sp->GetExecutionContextRef());
-    new_value_sp = ValueObject::CreateValueObjectFromExpression(
+    new_value_sp = value_sp->CreateChildValueObjectFromExpression(
         name, expression, exe_ctx, options.ref());
     if (new_value_sp)
       new_value_sp->SetName(ConstString(name));
@@ -456,7 +456,7 @@ lldb::SBValue SBValue::CreateValueFromAddress(const char *name,
   if (value_sp && type_impl_sp) {
     CompilerType ast_type(type_impl_sp->GetCompilerType(true));
     ExecutionContext exe_ctx(value_sp->GetExecutionContextRef());
-    new_value_sp = ValueObject::CreateValueObjectFromAddress(name, address,
+    new_value_sp = value_sp->CreateChildValueObjectFromAddress(name, address,
                                                              exe_ctx, ast_type);
   }
   sb_value.SetSP(new_value_sp);
@@ -474,7 +474,7 @@ lldb::SBValue SBValue::CreateValueFromData(const char *name, SBData data,
   lldb::TypeImplSP type_impl_sp(sb_type.GetSP());
   if (value_sp && type_impl_sp) {
     ExecutionContext exe_ctx(value_sp->GetExecutionContextRef());
-    new_value_sp = ValueObject::CreateValueObjectFromData(
+    new_value_sp = value_sp->CreateChildValueObjectFromData(
         name, **data, exe_ctx, type_impl_sp->GetCompilerType(true));
     new_value_sp->SetAddressTypeOfChildren(eAddressTypeLoad);
   }
@@ -508,7 +508,7 @@ lldb::SBValue SBValue::CreateBoolValue(const char *name, bool value) {
                      "cannot get a type system: {0}");
       return {};
     }
-    return ValueObject::CreateValueObjectFromBool(exe_ctx, *type_system_or_err,
+    return value_sp->CreateChildValueObjectFromBool(exe_ctx, *type_system_or_err,
                                                   value, name);
   };
   sb_value.SetSP(get_new_value());
diff --git a/lldb/source/DataFormatters/TypeSynthetic.cpp b/lldb/source/DataFormatters/TypeSynthetic.cpp
index 5f103ca6ac00a..afcb75ef52529 100644
--- a/lldb/source/DataFormatters/TypeSynthetic.cpp
+++ b/lldb/source/DataFormatters/TypeSynthetic.cpp
@@ -129,31 +129,32 @@ SyntheticChildrenFrontEnd::CalculateNumChildrenIgnoringErrors(uint32_t max) {
   return 0;
 }
 
-lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromExpression(
+lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateChildValueObjectFromExpression(
     llvm::StringRef name, llvm::StringRef expression,
     const ExecutionContext &exe_ctx) {
-  ValueObjectSP valobj_sp(
-      ValueObject::CreateValueObjectFromExpression(name, expression, exe_ctx));
+  EvaluateExpressionOptions options;
+  ValueObjectSP valobj_sp = m_backend.CreateChildValueObjectFromExpression(name, 
+    expression, exe_ctx, options);
   if (valobj_sp)
     valobj_sp->SetSyntheticChildrenGenerated(true);
   return valobj_sp;
 }
 
-lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromAddress(
+lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateChildValueObjectFromAddress(
     llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx,
     CompilerType type, bool do_deref) {
-  ValueObjectSP valobj_sp(ValueObject::CreateValueObjectFromAddress(
-      name, address, exe_ctx, type, do_deref));
+  ValueObjectSP valobj_sp = m_backend.CreateChildValueObjectFromAddress(
+      name, address, exe_ctx, type, do_deref);
   if (valobj_sp)
     valobj_sp->SetSyntheticChildrenGenerated(true);
   return valobj_sp;
 }
 
-lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromData(
+lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateChildValueObjectFromData(
     llvm::StringRef name, const DataExtractor &data,
     const ExecutionContext &exe_ctx, CompilerType type) {
-  ValueObjectSP valobj_sp(
-      ValueObject::CreateValueObjectFromData(name, data, exe_ctx, type));
+  ValueObjectSP valobj_sp = 
+  m_backend.CreateChildValueObjectFromData(name, data, exe_ctx, type);
   if (valobj_sp)
     valobj_sp->SetSyntheticChildrenGenerated(true);
   return valobj_sp;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp
index c49abd48082cd..4cca7aa46abf9 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp
@@ -167,11 +167,11 @@ lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::Update() {
       /*result_type=*/void_type, args,
       /*is_variadic=*/false, /*qualifiers=*/0);
   CompilerType coro_func_ptr_type = coro_func_type.GetPointerType();
-  ValueObjectSP resume_ptr_sp = CreateValueObjectFromAddress(
+  ValueObjectSP resume_ptr_sp = CreateChildValueObjectFromAddress(
       "resume", frame_ptr_addr + 0 * ptr_size, exe_ctx, coro_func_ptr_type);
   assert(resume_ptr_sp);
   m_children.push_back(std::move(resume_ptr_sp));
-  ValueObjectSP destroy_ptr_sp = CreateValueObjectFromAddress(
+  ValueObjectSP destroy_ptr_sp = CreateChildValueObjectFromAddress(
       "destroy", frame_ptr_addr + 1 * ptr_size, exe_ctx, coro_func_ptr_type);
   assert(destroy_ptr_sp);
   m_children.push_back(std::move(destroy_ptr_sp));
@@ -182,11 +182,11 @@ lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::Update() {
   // those pointers. We do so to avoid potential very deep recursion in case
   // there is a cycle formed between `std::coroutine_handle`s and their
   // promises.
-  ValueObjectSP promise_ptr_sp = CreateValueObjectFromAddress(
+  ValueObjectSP promise_ptr_sp = CreateChildValueObjectFromAddress(
       "promise", frame_ptr_addr + 2 * ptr_size, exe_ctx,
       promise_type.GetPointerType(), /*do_deref=*/false);
   m_children.push_back(std::move(promise_ptr_sp));
-  ValueObjectSP coroframe_ptr_sp = CreateValueObjectFromAddress(
+  ValueObjectSP coroframe_ptr_sp = CreateChildValueObjectFromAddress(
       "coro_frame", frame_ptr_addr, exe_ctx, coro_frame_type.GetPointerType(),
       /*do_deref=*/false);
   m_children.push_back(std::move(coroframe_ptr_sp));
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
index 1d522f0b4a724..d10c307b5256e 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
@@ -126,7 +126,7 @@ ValueObjectSP GenericBitsetFrontEnd::GetChildAtIndex(uint32_t idx) {
   uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx));
   DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size);
 
-  m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(),
+  m_elements[idx] = CreateChildValueObjectFromData(llvm::formatv("[{0}]", idx).str(),
                                               data, ctx, m_bool_type);
 
   return m_elements[idx];
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericInitializerList.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericInitializerList.cpp
index d3843c7e8f328..9d5eed384d88d 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericInitializerList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericInitializerList.cpp
@@ -88,7 +88,7 @@ class GenericInitializerListSyntheticFrontEnd
     offset = offset + m_start->GetValueAsUnsigned(0);
     StreamString name;
     name.Printf("[%" PRIu64 "]", (uint64_t)idx);
-    return CreateValueObjectFromAddress(name.GetString(), offset,
+    return CreateChildValueObjectFromAddress(name.GetString(), offset,
                                         m_backend.GetExecutionContextRef(),
                                         m_element_type);
   }
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
index e5ef393c09753..1f93d8a2404f8 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
@@ -328,7 +328,7 @@ ValueObjectSP LibCxxForwardListFrontEnd::GetChildAtIndex(uint32_t idx) {
   if (error.Fail())
     return nullptr;
 
-  return CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(), data,
+  return CreateChildValueObjectFromData(llvm::formatv("[{0}]", idx).str(), data,
                                    m_backend.GetExecutionContextRef(),
                                    m_element_type);
 }
@@ -435,7 +435,7 @@ lldb::ValueObjectSP LibCxxListFrontEnd::GetChildAtIndex(uint32_t idx) {
     addr = addr + 2 * process_sp->GetAddressByteSize();
     ExecutionContext exe_ctx(process_sp);
     current_sp =
-        CreateValueObjectFromAddress("__value_", addr, exe_ctx, m_element_type);
+        CreateChildValueObjectFromAddress("__value_", addr, exe_ctx, m_element_type);
     if (!current_sp)
       return lldb::ValueObjectSP();
   }
@@ -450,7 +450,7 @@ lldb::ValueObjectSP LibCxxListFrontEnd::GetChildAtIndex(uint32_t idx) {
 
   StreamString name;
   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
-  return CreateValueObjectFromData(name.GetString(), data,
+  return CreateChildValueObjectFromData(name.GetString(), data,
                                    m_backend.GetExecutionContextRef(),
                                    m_element_type);
 }
@@ -519,7 +519,7 @@ ValueObjectSP MsvcStlForwardListFrontEnd::GetChildAtIndex(uint32_t idx) {
   if (error.Fail())
     return nullptr;
 
-  return CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(), data,
+  return CreateChildValueObjectFromData(llvm::formatv("[{0}]", idx).str(), data,
                                    m_backend.GetExecutionContextRef(),
                                    m_element_type);
 }
@@ -590,7 +590,7 @@ lldb::ValueObjectSP MsvcStlListFrontEnd::GetChildAtIndex(uint32_t idx) {
 
   StreamString name;
   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
-  return CreateValueObjectFromData(name.GetString(), data,
+  return CreateChildValueObjectFromData(name.GetString(), data,
                                    m_backend.GetExecutionContextRef(),
                                    m_element_type);
 }
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp
index b1ed55522fe29..bb99c876b5193 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp
@@ -108,7 +108,7 @@ lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::GetChildAtIndex(
   uint64_t offset = idx * m_element_size_size_t;
   offset = offset + m_start->GetValueAsUnsigned(0);
 
-  lldb::ValueObjectSP indirect = CreateValueObjectFromAddress(
+  lldb::ValueObjectSP indirect = CreateChildValueObjectFromAddress(
       "", offset, m_backend.GetExecutionContextRef(), m_element_type_size_t);
   if (!indirect)
     return lldb::ValueObjectSP();
@@ -122,7 +122,7 @@ lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::GetChildAtIndex(
 
   StreamString name;
   name.Printf("[%" PRIu64 "] -> [%zu]", (uint64_t)idx, value);
-  return CreateValueObjectFromAddress(name.GetString(), offset,
+  return CreateChildValueObjectFromAddress(name.GetString(), offset,
                                       m_backend.GetExecutionContextRef(),
                                       m_element_type);
 }
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp
index a96c15e377a74..647f1401f0906 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp
@@ -110,7 +110,7 @@ lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::GetChildAtIndex(
   offset = offset + m_start->GetValueAsUnsigned(0);
   StreamString name;
   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
-  return CreateValueObjectFromAddress(name.GetString(), offset,
+  return CreateChildValueObjectFromAddress(name.GetString(), offset,
                                       m_backend.GetExecutionContextRef(),
                                       m_element_type);
 }
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp
index cfca43b71fdea..3d3ebfbc248af 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp
@@ -87,7 +87,7 @@ lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::GetChildAtIndex(
   offset = offset + m_start->GetValueAsUnsigned(0);
   StreamString name;
   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
-  return CreateValueObjectFromAddress(name.GetString(), offset,
+  return CreateChildValueObjectFromAddress(name.GetString(), offset,
                                       m_backend.GetExecutionContextRef(),
                                       m_element_type);
 }
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
index 8fef4d13802d5..91af6d44edf32 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -210,7 +210,7 @@ lldb::ValueObjectSP lldb_private::formatters::
   const bool thread_and_frame_only_if_stopped = true;
   ExecutionContext exe_ctx =
       val_hash->GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped);
-  return CreateValueObjectFromData(stream.GetString(), data, exe_ctx,
+  return CreateChildValueObjectFromData(stream.GetString(), data, exe_ctx,
                                    m_element_type);
 }
 
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp
index d4b3c23b94b02..06eba08ea7ae3 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp
@@ -91,7 +91,7 @@ lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::GetChildAtIndex(
   offset = offset + m_start->GetValueAsUnsigned(0);
   StreamString name;
   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
-  return CreateValueObjectFromAddress(name.GetString(), offset,
+  return CreateChildValueObjectFromAddress(name.GetString(), offset,
                                       m_backend.GetExecutionContextRef(),
                                       m_element_type);
 }
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
index 78949a455c443..f9a6df245b7f9 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -121,7 +121,7 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex(
   offset = offset + m_start->GetValueAsUnsigned(0);
   StreamString name;
   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
-  return CreateValueObjectFromAddress(name.GetString(), offset,
+  return CreateChildValueObjectFromAddress(name.GetString(), offset,
                                       m_backend.GetExecutionContextRef(),
                                       m_element_type);
 }
@@ -228,11 +228,11 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex(
   }
   StreamString name;
   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
-  ValueObjectSP retval_sp(CreateValueObjectFromData(
+  ValueObjectSP retval_sp = CreateChildValueObjectFromData(
       name.GetString(),
       DataExtractor(buffer_sp, process_sp->GetByteOrder(),
                     process_sp->GetAddressByteSize()),
-      m_exe_ctx_ref, m_bool_type));
+      m_exe_ctx_ref, m_bool_type);
   if (retval_sp)
     m_children[idx] = retval_sp;
   return retval_sp;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
index f0701da4ae22f..2f0a4fb66939d 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
@@ -143,7 +143,7 @@ lldb::ValueObjectSP
 LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
   if (m_pair_address != 0 && m_pair_type) {
     if (!m_pair_sp)
-      m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address,
+      m_pair_sp = CreateChildValueObjectFromAddress("pair", m_pair_address,
                                                m_exe_ctx_ref, m_pair_type);
     if (m_pair_sp)
       return m_pair_sp->GetChildAtIndex(idx);
@@ -210,7 +210,7 @@ lldb::ChildCacheState VectorIteratorSyntheticFrontEnd::Update() {
     return lldb::ChildCacheState::eRefetch;
   Status err;
   m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
-  m_item_sp = CreateValueObjectFromAddress(
+  m_item_sp = CreateChildValueObjectFromAddress(
       "item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref,
       item_ptr->GetCompilerType().GetPointeeType());
   if (err.Fail())
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp
index 6d6a183ad2413..3bc7a3f6d77eb 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp
@@ -42,7 +42,7 @@ class LibStdcppSpanSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
     uint64_t offset = (static_cast<uint64_t>(idx) * m_element_size);
     offset += m_start->GetValueAsUnsigned(0);
     const std::string name = llvm::formatv("[{0}]", idx);
-    return CreateValueObjectFromAddress(
+    return CreateChildValueObjectFromAddress(
         name, offset, m_backend.GetExecutionContextRef(), m_element_type);
   }
 
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp
index ed5d6ff1a4f10..381e6b118f89a 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp
@@ -86,7 +86,7 @@ lldb_private::formatters::MsvcStlDequeSyntheticFrontEnd::GetChildAtIndex(
 
   StreamString name;
   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
-  return CreateValueObjectFromAddress(name.GetString(), second_address,
+  return CreateChildValueObjectFromAddress(name.GetString(), second_address,
                                       m_backend.GetExecutionContextRef(),
                                       m_element_type);
 }
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSpan.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSpan.cpp
index 4280e6cbdfc1c..4db6b1e67fba3 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSpan.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlSpan.cpp
@@ -60,7 +60,7 @@ lldb_private::formatters::MsvcStlSpanSyntheticFrontEnd::GetChildAtIndex(
   offset = offset + m_start->GetValueAsUnsigned(0);
   StreamString name;
   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
-  return CreateValueObjectFromAddress(name.GetString(), offset,
+  return CreateChildValueObjectFromAddress(name.GetString(), offset,
                                       m_backend.GetExecutionContextRef(),
                                       m_element_type);
 }
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVector.cpp
index a5e909a7ae05e..7a31d69c3a06c 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVector.cpp
@@ -107,7 +107,7 @@ lldb_private::formatters::MsvcStlVectorSyntheticFrontEnd::GetChildAtIndex(
   offset = offset + m_start->GetValueAsUnsigned(0);
   StreamString name;
   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
-  return CreateValueObjectFromAddress(name.GetString(), offset,
+  return CreateChildValueObjectFromAddress(name.GetString(), offset,
                                       m_backend.GetExecutionContextRef(),
                                       m_element_type);
 }
@@ -208,11 +208,11 @@ lldb_private::formatters::MsvcStlVectorBoolSyntheticFrontEnd::GetChildAtIndex(
   }
   StreamString name;
   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
-  ValueObjectSP retval_sp(CreateValueObjectFromData(
+  ValueObjectSP retval_sp = CreateChildValueObjectFromData(
       name.GetString(),
       DataExtractor(buffer_sp, process_sp->GetByteOrder(),
                     process_sp->GetAddressByteSize()),
-      m_exe_ctx_ref, m_bool_type));
+      m_exe_ctx_ref, m_bool_type);
   if (retval_sp)
     m_children[idx] = retval_sp;
   return retval_sp;
diff --git a/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/lldb/source/Plugins/Language/ObjC/NSArray.cpp
index b1dc9ff7e48bf..90e83445ccb0b 100644
--- a/lldb/source/Plugins/Language/ObjC/NSArray.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSArray.cpp
@@ -485,7 +485,7 @@ lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetChildAtIndex(
   object_at_idx += (pyhs_idx * m_ptr_size);
   StreamString idx_name;
   idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
-  return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
+  return CreateChildValueObjectFromAddress(idx_name.GetString(), object_at_idx,
                                       m_exe_ctx_ref, m_id_type);
 }
 
@@ -662,7 +662,7 @@ lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
     return lldb::ValueObjectSP();
   StreamString idx_name;
   idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
-  return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
+  return CreateChildValueObjectFromAddress(idx_name.GetString(), object_at_idx,
                                       m_exe_ctx_ref, m_id_type);
 }
 
diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
index e38cd103f11d7..26e28b5e76e88 100644
--- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
@@ -690,7 +690,7 @@ lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex(
     StreamString idx_name;
     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
     DataExtractor data(buffer_sp, m_order, m_ptr_size);
-    dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
+    dict_item.valobj_sp = CreateChildValueObjectFromData(idx_name.GetString(), data,
                                                     m_exe_ctx_ref, m_pair_type);
   }
   return dict_item.valobj_sp;
@@ -813,7 +813,7 @@ lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex(
     StreamString idx_name;
     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
     DataExtractor data(buffer_sp, m_order, m_ptr_size);
-    dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
+    dict_item.valobj_sp = CreateChildValueObjectFromData(idx_name.GetString(), data,
                                                     m_exe_ctx_ref, m_pair_type);
   }
   return dict_item.valobj_sp;
@@ -916,7 +916,7 @@ lldb::ValueObjectSP lldb_private::formatters::
     StreamString idx_name;
     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
     DataExtractor data(buffer_sp, m_order, m_ptr_size);
-    dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
+    dict_item.valobj_sp = CreateChildValueObjectFromData(idx_name.GetString(), data,
                                                     m_exe_ctx_ref, m_pair_type);
   }
   return dict_item.valobj_sp;
@@ -989,7 +989,7 @@ lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex(
   }
 
   DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);
-  m_pair = CreateValueObjectFromData(
+  m_pair = CreateChildValueObjectFromData(
       "[0]", data, m_backend.GetExecutionContextRef(), pair_type);
 
   return m_pair;
@@ -1141,7 +1141,7 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
     StreamString idx_name;
     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
     DataExtractor data(buffer_sp, m_order, m_ptr_size);
-    dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
+    dict_item.valobj_sp = CreateChildValueObjectFromData(idx_name.GetString(), data,
                                                     m_exe_ctx_ref, m_pair_type);
   }
   return dict_item.valobj_sp;
@@ -1277,7 +1277,7 @@ lldb_private::formatters::Foundation1100::
     StreamString idx_name;
     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
     DataExtractor data(buffer_sp, m_order, m_ptr_size);
-    dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
+    dict_item.valobj_sp = CreateChildValueObjectFromData(idx_name.GetString(), data,
                                                     m_exe_ctx_ref, m_pair_type);
   }
   return dict_item.valobj_sp;
diff --git a/lldb/source/Plugins/Language/ObjC/NSError.cpp b/lldb/source/Plugins/Language/ObjC/NSError.cpp
index e4744fdfc62f6..03c662a519537 100644
--- a/lldb/source/Plugins/Language/ObjC/NSError.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSError.cpp
@@ -156,7 +156,7 @@ class NSErrorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
         ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget());
     if (!scratch_ts_sp)
       return lldb::ChildCacheState::eRefetch;
-    m_child_sp = CreateValueObjectFromData(
+    m_child_sp = CreateChildValueObjectFromData(
         "_userInfo", isw.GetAsData(process_sp->GetByteOrder()),
         m_backend.GetExecutionContextRef(),
         scratch_ts_sp->GetBasicType(lldb::eBasicTypeObjCID));
diff --git a/lldb/source/Plugins/Language/ObjC/NSException.cpp b/lldb/source/Plugins/Language/ObjC/NSException.cpp
index 935e0c6975501..725aca4167c04 100644
--- a/lldb/source/Plugins/Language/ObjC/NSException.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSException.cpp
@@ -31,7 +31,7 @@ using namespace lldb_private::formatters;
 
 static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp,
                           ValueObjectSP *reason_sp, ValueObjectSP *userinfo_sp,
-                          ValueObjectSP *reserved_sp) {
+                          ValueObjectSP *reserved_sp, bool owned_by_valobj) {
   ProcessSP process_sp(valobj.GetProcessSP());
   if (!process_sp)
     return false;
@@ -77,31 +77,49 @@ static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp,
 
   CompilerType voidstar =
       scratch_ts_sp->GetBasicType(lldb::eBasicTypeVoid).GetPointerType();
-
-  if (name_sp)
-    *name_sp = ValueObject::CreateValueObjectFromData(
-        "name", name_isw.GetAsData(process_sp->GetByteOrder()),
-        valobj.GetExecutionContextRef(), voidstar);
-  if (reason_sp)
-    *reason_sp = ValueObject::CreateValueObjectFromData(
-        "reason", reason_isw.GetAsData(process_sp->GetByteOrder()),
-        valobj.GetExecutionContextRef(), voidstar);
-  if (userinfo_sp)
-    *userinfo_sp = ValueObject::CreateValueObjectFromData(
-        "userInfo", userinfo_isw.GetAsData(process_sp->GetByteOrder()),
-        valobj.GetExecutionContextRef(), voidstar);
-  if (reserved_sp)
-    *reserved_sp = ValueObject::CreateValueObjectFromData(
-        "reserved", reserved_isw.GetAsData(process_sp->GetByteOrder()),
-        valobj.GetExecutionContextRef(), voidstar);
-
+  if (owned_by_valobj) {
+    if (name_sp)
+      *name_sp = valobj.CreateChildValueObjectFromData(
+          "name", name_isw.GetAsData(process_sp->GetByteOrder()),
+          valobj.GetExecutionContextRef(), voidstar);
+    if (reason_sp)
+      *reason_sp = valobj.CreateChildValueObjectFromData(
+          "reason", reason_isw.GetAsData(process_sp->GetByteOrder()),
+          valobj.GetExecutionContextRef(), voidstar);
+    if (userinfo_sp)
+      *userinfo_sp = valobj.CreateChildValueObjectFromData(
+          "userInfo", userinfo_isw.GetAsData(process_sp->GetByteOrder()),
+          valobj.GetExecutionContextRef(), voidstar);
+    if (reserved_sp)
+      *reserved_sp = valobj.CreateChildValueObjectFromData(
+          "reserved", reserved_isw.GetAsData(process_sp->GetByteOrder()),
+          valobj.GetExecutionContextRef(), voidstar);
+  } else {
+    if (name_sp)
+      *name_sp = ValueObject::CreateValueObjectFromData(
+          "name", name_isw.GetAsData(process_sp->GetByteOrder()),
+          valobj.GetExecutionContextRef(), voidstar);
+    if (reason_sp)
+      *reason_sp = ValueObject::CreateValueObjectFromData(
+          "reason", reason_isw.GetAsData(process_sp->GetByteOrder()),
+          valobj.GetExecutionContextRef(), voidstar);
+    if (userinfo_sp)
+      *userinfo_sp = ValueObject::CreateValueObjectFromData(
+          "userInfo", userinfo_isw.GetAsData(process_sp->GetByteOrder()),
+          valobj.GetExecutionContextRef(), voidstar);
+    if (reserved_sp)
+      *reserved_sp = ValueObject::CreateValueObjectFromData(
+          "reserved", reserved_isw.GetAsData(process_sp->GetByteOrder()),
+          valobj.GetExecutionContextRef(), voidstar);
+  }
   return true;
 }
 
 bool lldb_private::formatters::NSException_SummaryProvider(
     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
   lldb::ValueObjectSP reason_sp;
-  if (!ExtractFields(valobj, nullptr, &reason_sp, nullptr, nullptr))
+  if (!ExtractFields(valobj, nullptr, &reason_sp, nullptr, nullptr, 
+                     /*owned_by_valobj=*/ false))
     return false;
 
   if (!reason_sp) {
@@ -144,7 +162,8 @@ class NSExceptionSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
     m_reserved_sp.reset();
 
     const auto ret = ExtractFields(m_backend, &m_name_sp, &m_reason_sp,
-                                   &m_userinfo_sp, &m_reserved_sp);
+                                   &m_userinfo_sp, &m_reserved_sp,
+                                   /*owned_by_valobj=*/ true);
 
     return ret ? lldb::ChildCacheState::eReuse
                : lldb::ChildCacheState::eRefetch;
diff --git a/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp b/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp
index 23f711931f956..70316c4f10f2e 100644
--- a/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp
@@ -45,7 +45,7 @@ class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
   }
 
   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
-    return m_impl.GetIndexAtIndex(idx, m_uint_star_type);
+    return m_impl.GetIndexAtIndex(idx, m_uint_star_type, m_backend);
   }
 
   lldb::ChildCacheState Update() override {
@@ -146,14 +146,15 @@ class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
     }
 
     lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
-                                        const CompilerType &desired_type) {
+                                        const CompilerType &desired_type,
+                                        ValueObject &parent) {
       if (idx >= GetNumIndexes())
         return nullptr;
       switch (m_mode) {
       default:
         return nullptr;
       case Mode::Inlined:
-        return m_inlined.GetIndexAtIndex(idx, desired_type);
+        return m_inlined.GetIndexAtIndex(idx, desired_type, parent);
       case Mode::Outsourced:
         return m_outsourced.GetIndexAtIndex(idx);
       }
@@ -161,6 +162,7 @@ class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
 
     struct InlinedIndexes {
     public:
+      
       void SetIndexes(uint64_t value, Process &p) {
         m_indexes = value;
         _lengthForInlinePayload(p.GetAddressByteSize());
@@ -170,7 +172,8 @@ class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
       size_t GetNumIndexes() { return m_count; }
 
       lldb::ValueObjectSP GetIndexAtIndex(size_t idx,
-                                          const CompilerType &desired_type) {
+                                          const CompilerType &desired_type,
+                                          ValueObject &parent) {
         if (!m_process)
           return nullptr;
 
@@ -178,22 +181,18 @@ class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
         if (!value.second)
           return nullptr;
 
-        Value v;
+        Scalar scalar;
         if (m_ptr_size == 8) {
-          Scalar scalar((unsigned long long)value.first);
-          v = Value(scalar);
+          scalar = Scalar((unsigned long long)value.first);
         } else {
-          Scalar scalar((unsigned int)value.first);
-          v = Value(scalar);
+          scalar = Scalar((unsigned int)value.first);
         }
 
-        v.SetCompilerType(desired_type);
-
         StreamString idx_name;
         idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
 
-        return ValueObjectConstResult::Create(
-            m_process, v, ConstString(idx_name.GetString()));
+        return parent.CreateChildValueObjectFromScalar(
+            m_process, scalar, desired_type, idx_name.GetString());
       }
 
       void Clear() {
diff --git a/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/lldb/source/Plugins/Language/ObjC/NSSet.cpp
index 44af668759f96..3477cf1c577d4 100644
--- a/lldb/source/Plugins/Language/ObjC/NSSet.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSSet.cpp
@@ -488,7 +488,7 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(
                        process_sp->GetByteOrder(),
                        process_sp->GetAddressByteSize());
 
-    set_item.valobj_sp = CreateValueObjectFromData(
+    set_item.valobj_sp = CreateChildValueObjectFromData(
         idx_name.GetString(), data, m_exe_ctx_ref,
         m_backend.GetCompilerType().GetBasicTypeFromAST(
             lldb::eBasicTypeObjCID));
@@ -598,7 +598,7 @@ lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetChildAtIndex(
 
     DataExtractor data(buffer_sp, m_order, m_ptr_size);
 
-    set_item.valobj_sp = CreateValueObjectFromData(
+    set_item.valobj_sp = CreateChildValueObjectFromData(
         idx_name.GetString(), data, m_exe_ctx_ref,
         m_backend.GetCompilerType().GetBasicTypeFromAST(
             lldb::eBasicTypeObjCID));
@@ -738,7 +738,7 @@ lldb_private::formatters::
                        process_sp->GetByteOrder(),
                        process_sp->GetAddressByteSize());
 
-    set_item.valobj_sp = CreateValueObjectFromData(
+    set_item.valobj_sp = CreateChildValueObjectFromData(
         idx_name.GetString(), data, m_exe_ctx_ref,
         m_backend.GetCompilerType().GetBasicTypeFromAST(
             lldb::eBasicTypeObjCID));
diff --git a/lldb/source/Plugins/Language/ObjC/NSString.cpp b/lldb/source/Plugins/Language/ObjC/NSString.cpp
index b7cc0062a9e68..ce268ac7f3257 100644
--- a/lldb/source/Plugins/Language/ObjC/NSString.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSString.cpp
@@ -292,7 +292,7 @@ bool lldb_private::formatters::NSAttributedStringSummaryProvider(
   pointer_value += addr_size;
   CompilerType type(valobj.GetCompilerType());
   ExecutionContext exe_ctx(target_sp, false);
-  ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress(
+  ValueObjectSP child_ptr_sp(valobj.CreateChildValueObjectFromAddress(
       "string_ptr", pointer_value, exe_ctx, type));
   if (!child_ptr_sp)
     return false;
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index cad86bf956e38..b093cd2ba8c47 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -5295,6 +5295,17 @@ void TargetProperties::SetDebugUtilityExpression(bool debug) {
   SetPropertyAtIndex(idx, debug);
 }
 
+bool TargetProperties::GetCheckValueObjectOwnership() const {
+  const uint32_t idx = ePropertyCheckValueObjectOwnership;
+  return GetPropertyAtIndexAs<bool>(
+      idx, g_target_properties[idx].default_uint_value != 0);
+}
+
+void TargetProperties::SetCheckValueObjectOwnership(bool check) {
+  const uint32_t idx = ePropertyCheckValueObjectOwnership;
+  SetPropertyAtIndex(idx, check);
+}
+
 std::optional<LoadScriptFromSymFile>
 TargetProperties::GetAutoLoadScriptsForModule(
     llvm::StringRef module_name) const {
diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td
index e36d233fc2469..f4e1908a99c3a 100644
--- a/lldb/source/Target/TargetProperties.td
+++ b/lldb/source/Target/TargetProperties.td
@@ -169,6 +169,9 @@ let Definition = "target", Path = "target" in {
   def UseHexImmediates: Property<"use-hex-immediates", "Boolean">,
     DefaultTrue,
     Desc<"Show immediates in disassembly as hexadecimal.">;
+  def CheckValueObjectOwnership: Property<"check-vo-ownership", "Boolean">,
+    DefaultFalse,
+    Desc<"Check that ValueObject children are managed by their parents.">;
   def HexImmediateStyle: Property<"hex-immediate-style", "Enum">,
     DefaultEnumValue<"Disassembler::eHexStyleC">,
     EnumValues<"OptionEnumValues(g_hex_immediate_style_values)">,
diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp
index 6a12a2e45b2e1..638cd1e06ea06 100644
--- a/lldb/source/ValueObject/ValueObject.cpp
+++ b/lldb/source/ValueObject/ValueObject.cpp
@@ -377,6 +377,23 @@ bool ValueObject::IsLogicalTrue(Status &error) {
   return ret;
 }
 
+ValueObjectSP ValueObject::CheckValueObjectOwnership(ValueObject *child) {
+  if (GetTargetSP()->GetCheckValueObjectOwnership()) {
+    // Child value objects should always be owned by their parent's manager.
+    if (child && (child->GetManager() != GetManager())) {
+      Status error = 
+        Status::FromErrorStringWithFormatv(
+            "ValueObject: '{0}' not owned by its parent: '{1}'",
+            child->GetName(), GetName());
+      ValueObjectSP ret_sp = 
+          ValueObjectConstResult::Create(GetTargetSP().get(), std::move(error), 
+              this->GetManager());
+      return ret_sp;
+    }
+  }
+  return {};
+}
+
 ValueObjectSP ValueObject::GetChildAtIndex(uint32_t idx, bool can_create) {
   ValueObjectSP child_sp;
   // We may need to update our value if we are dynamic
@@ -2908,7 +2925,8 @@ ValueObjectSP ValueObject::AddressOf(Status &error) {
         m_addr_of_valobj_sp = ValueObjectConstResult::Create(
             exe_ctx.GetBestExecutionContextScope(),
             compiler_type.GetPointerType(), ConstString(name.c_str()), buffer,
-            endian::InlHostByteOrder(), exe_ctx.GetAddressByteSize());
+            endian::InlHostByteOrder(), exe_ctx.GetAddressByteSize(),
+            LLDB_INVALID_ADDRESS, this->GetManager());
       }
     } break;
     default:
@@ -3524,20 +3542,29 @@ SymbolContextScope *ValueObject::GetSymbolContextScope() {
 lldb::ValueObjectSP
 ValueObject::CreateValueObjectFromExpression(llvm::StringRef name,
                                              llvm::StringRef expression,
-                                             const ExecutionContext &exe_ctx) {
+                                             const ExecutionContext &exe_ctx,
+                                             ValueObject *parent) {
   return CreateValueObjectFromExpression(name, expression, exe_ctx,
-                                         EvaluateExpressionOptions());
+                                         EvaluateExpressionOptions(),
+                                         parent);
 }
 
 lldb::ValueObjectSP ValueObject::CreateValueObjectFromExpression(
     llvm::StringRef name, llvm::StringRef expression,
-    const ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options) {
+    const ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options,
+    ValueObject *parent) {
+  // FIXME: I haven't handled parent in this case yet.  That is a WHOLE lot of
+  // plumbing.
+
   lldb::ValueObjectSP retval_sp;
   lldb::TargetSP target_sp(exe_ctx.GetTargetSP());
   if (!target_sp)
     return retval_sp;
   if (expression.empty())
     return retval_sp;
+  if (parent)
+    retval_sp = parent->GetSP();
+
   target_sp->EvaluateExpression(expression, exe_ctx.GetFrameSP().get(),
                                 retval_sp, options);
   if (retval_sp && !name.empty())
@@ -3547,7 +3574,7 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromExpression(
 
 lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress(
     llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx,
-    CompilerType type, bool do_deref) {
+    CompilerType type, bool do_deref, ValueObject *parent) {
   if (type) {
     CompilerType pointer_type(type.GetPointerType());
     if (!do_deref)
@@ -3558,7 +3585,8 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress(
       lldb::ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create(
           exe_ctx.GetBestExecutionContextScope(), pointer_type,
           ConstString(name), buffer, exe_ctx.GetByteOrder(),
-          exe_ctx.GetAddressByteSize()));
+          exe_ctx.GetAddressByteSize(), /*address=*/ LLDB_INVALID_ADDRESS,
+          parent ? parent->GetManager() : nullptr));
       if (ptr_result_valobj_sp) {
         if (do_deref)
           ptr_result_valobj_sp->GetValue().SetValueType(
@@ -3577,11 +3605,11 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress(
 
 lldb::ValueObjectSP ValueObject::CreateValueObjectFromData(
     llvm::StringRef name, const DataExtractor &data,
-    const ExecutionContext &exe_ctx, CompilerType type) {
+    const ExecutionContext &exe_ctx, CompilerType type, ValueObject *parent) {
   lldb::ValueObjectSP new_value_sp;
   new_value_sp = ValueObjectConstResult::Create(
       exe_ctx.GetBestExecutionContextScope(), type, ConstString(name), data,
-      LLDB_INVALID_ADDRESS);
+      LLDB_INVALID_ADDRESS, parent ? parent->GetManager() : nullptr);
   new_value_sp->SetAddressTypeOfChildren(eAddressTypeLoad);
   if (new_value_sp && !name.empty())
     new_value_sp->SetName(ConstString(name));
@@ -3591,7 +3619,8 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromData(
 lldb::ValueObjectSP
 ValueObject::CreateValueObjectFromAPInt(const ExecutionContext &exe_ctx,
                                         const llvm::APInt &v, CompilerType type,
-                                        llvm::StringRef name) {
+                                        llvm::StringRef name,
+                                        ValueObject *parent) {
   uint64_t byte_size =
       llvm::expectedToOptional(
           type.GetByteSize(exe_ctx.GetBestExecutionContextScope()))
@@ -3599,27 +3628,31 @@ ValueObject::CreateValueObjectFromAPInt(const ExecutionContext &exe_ctx,
   lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
       reinterpret_cast<const void *>(v.getRawData()), byte_size,
       exe_ctx.GetByteOrder(), exe_ctx.GetAddressByteSize());
-  return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type);
+  return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type, parent);
 }
 
 lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPFloat(
     const ExecutionContext &exe_ctx, const llvm::APFloat &v, CompilerType type,
-    llvm::StringRef name) {
-  return CreateValueObjectFromAPInt(exe_ctx, v.bitcastToAPInt(), type, name);
+    llvm::StringRef name, ValueObject *parent) {
+  return CreateValueObjectFromAPInt(exe_ctx, v.bitcastToAPInt(), type, name, parent);
 }
 
 lldb::ValueObjectSP
 ValueObject::CreateValueObjectFromScalar(const ExecutionContext &exe_ctx,
                                          Scalar &s, CompilerType type,
-                                         llvm::StringRef name) {
+                                         llvm::StringRef name,
+                                         ValueObject *parent) {
   return ValueObjectConstResult::Create(exe_ctx.GetBestExecutionContextScope(),
-                                        type, s, ConstString(name));
+                                        type, s, ConstString(name), 
+                                        /*module_ptr=*/ nullptr, 
+                                        parent ? parent->GetManager() : nullptr);
 }
 
 lldb::ValueObjectSP
 ValueObject::CreateValueObjectFromBool(const ExecutionContext &exe_ctx,
                                        TypeSystemSP typesystem_sp, bool value,
-                                       llvm::StringRef name) {
+                                       llvm::StringRef name,
+                                       ValueObject *parent) {
   CompilerType type = typesystem_sp->GetBasicTypeFromAST(lldb::eBasicTypeBool);
   ExecutionContextScope *exe_scope = exe_ctx.GetBestExecutionContextScope();
   uint64_t byte_size =
@@ -3627,11 +3660,12 @@ ValueObject::CreateValueObjectFromBool(const ExecutionContext &exe_ctx,
   lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
       reinterpret_cast<const void *>(&value), byte_size, exe_ctx.GetByteOrder(),
       exe_ctx.GetAddressByteSize());
-  return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type);
+  return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type, parent);
 }
 
 lldb::ValueObjectSP ValueObject::CreateValueObjectFromNullptr(
-    const ExecutionContext &exe_ctx, CompilerType type, llvm::StringRef name) {
+    const ExecutionContext &exe_ctx, CompilerType type, llvm::StringRef name,
+    ValueObject *parent) {
   if (!type.IsNullPtrType()) {
     lldb::ValueObjectSP ret_val;
     return ret_val;
@@ -3644,7 +3678,7 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromNullptr(
   lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
       reinterpret_cast<const void *>(zero), byte_size, exe_ctx.GetByteOrder(),
       exe_ctx.GetAddressByteSize());
-  return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type);
+  return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type, parent);
 }
 
 ModuleSP ValueObject::GetModule() {
diff --git a/lldb/source/ValueObject/ValueObjectConstResult.cpp b/lldb/source/ValueObject/ValueObjectConstResult.cpp
index 10a62970edcbb..e8f17f96f3be4 100644
--- a/lldb/source/ValueObject/ValueObjectConstResult.cpp
+++ b/lldb/source/ValueObject/ValueObjectConstResult.cpp
@@ -29,9 +29,14 @@ using namespace lldb_private;
 ValueObjectSP ValueObjectConstResult::Create(ExecutionContextScope *exe_scope,
                                              ByteOrder byte_order,
                                              uint32_t addr_byte_size,
-                                             lldb::addr_t address) {
-  auto manager_sp = ValueObjectManager::Create();
-  return (new ValueObjectConstResult(exe_scope, *manager_sp, byte_order,
+                                             lldb::addr_t address,
+                                             ValueObjectManager *manager) {
+  std::shared_ptr<ValueObjectManager> manager_sp;
+  if (!manager) {
+    manager_sp = ValueObjectManager::Create();
+    manager = manager_sp.get();
+  }
+  return (new ValueObjectConstResult(exe_scope, *manager, byte_order,
                                      addr_byte_size, address))
       ->GetSP();
 }
@@ -53,9 +58,14 @@ ValueObjectSP ValueObjectConstResult::Create(ExecutionContextScope *exe_scope,
                                              const CompilerType &compiler_type,
                                              ConstString name,
                                              const DataExtractor &data,
-                                             lldb::addr_t address) {
-  auto manager_sp = ValueObjectManager::Create();
-  return (new ValueObjectConstResult(exe_scope, *manager_sp, compiler_type,
+                                             lldb::addr_t address,
+                                             ValueObjectManager *manager) {
+  std::shared_ptr<ValueObjectManager> manager_sp;
+  if (!manager) {
+    manager_sp = ValueObjectManager::Create();
+    manager = manager_sp.get();
+  }
+  return (new ValueObjectConstResult(exe_scope, *manager, compiler_type,
                                      name, data, address))
       ->GetSP();
 }
@@ -88,9 +98,14 @@ ValueObjectSP ValueObjectConstResult::Create(ExecutionContextScope *exe_scope,
                                              const lldb::DataBufferSP &data_sp,
                                              lldb::ByteOrder data_byte_order,
                                              uint32_t data_addr_size,
-                                             lldb::addr_t address) {
-  auto manager_sp = ValueObjectManager::Create();
-  return (new ValueObjectConstResult(exe_scope, *manager_sp, compiler_type,
+                                             lldb::addr_t address,
+                                             ValueObjectManager *manager) {
+  std::shared_ptr<ValueObjectManager> manager_sp;
+  if (!manager) {
+    manager_sp = ValueObjectManager::Create();
+    manager = manager_sp.get();
+  }
+  return (new ValueObjectConstResult(exe_scope, *manager, compiler_type,
                                      name, data_sp, data_byte_order,
                                      data_addr_size, address))
       ->GetSP();
@@ -98,9 +113,14 @@ ValueObjectSP ValueObjectConstResult::Create(ExecutionContextScope *exe_scope,
 
 ValueObjectSP ValueObjectConstResult::Create(ExecutionContextScope *exe_scope,
                                              Value &value, ConstString name,
-                                             Module *module) {
-  auto manager_sp = ValueObjectManager::Create();
-  return (new ValueObjectConstResult(exe_scope, *manager_sp, value, name,
+                                             Module *module,
+                                             ValueObjectManager *manager) {
+  std::shared_ptr<ValueObjectManager> manager_sp;
+  if (!manager) {
+    manager_sp = ValueObjectManager::Create();
+    manager = manager_sp.get();
+  }
+  return (new ValueObjectConstResult(exe_scope, *manager, value, name,
                                      module))
       ->GetSP();
 }
@@ -108,9 +128,14 @@ ValueObjectSP ValueObjectConstResult::Create(ExecutionContextScope *exe_scope,
 ValueObjectSP ValueObjectConstResult::Create(ExecutionContextScope *exe_scope,
                                              const CompilerType &compiler_type,
                                              Scalar &scalar, ConstString name,
-                                             Module *module) {
-  auto manager_sp = ValueObjectManager::Create();
-  return (new ValueObjectConstResult(exe_scope, *manager_sp, compiler_type,
+                                             Module *module,
+                                             ValueObjectManager *manager) {
+  std::shared_ptr<ValueObjectManager> manager_sp;
+  if (!manager) {
+    manager_sp = ValueObjectManager::Create();
+    manager = manager_sp.get();
+  }
+  return (new ValueObjectConstResult(exe_scope, *manager, compiler_type,
                                      scalar, name, module))
       ->GetSP();
 }
@@ -138,9 +163,14 @@ ValueObjectSP ValueObjectConstResult::Create(ExecutionContextScope *exe_scope,
                                              ConstString name,
                                              lldb::addr_t address,
                                              AddressType address_type,
-                                             uint32_t addr_byte_size) {
-  auto manager_sp = ValueObjectManager::Create();
-  return (new ValueObjectConstResult(exe_scope, *manager_sp, compiler_type,
+                                             uint32_t addr_byte_size,
+                                             ValueObjectManager *manager) {
+  std::shared_ptr<ValueObjectManager> manager_sp;
+  if (!manager) {
+    manager_sp = ValueObjectManager::Create();
+    manager = manager_sp.get();
+  }
+  return (new ValueObjectConstResult(exe_scope, *manager, compiler_type,
                                      name, address, address_type,
                                      addr_byte_size))
       ->GetSP();
@@ -177,9 +207,15 @@ ValueObjectConstResult::ValueObjectConstResult(
 }
 
 ValueObjectSP ValueObjectConstResult::Create(ExecutionContextScope *exe_scope,
-                                             Status &&error) {
-  auto manager_sp = ValueObjectManager::Create();
-  return (new ValueObjectConstResult(exe_scope, *manager_sp, std::move(error)))
+                                             Status &&error, 
+                                             ValueObjectManager *manager) {
+
+  std::shared_ptr<ValueObjectManager> manager_sp;
+  if (!manager) {
+    manager_sp = ValueObjectManager::Create();
+    manager = manager_sp.get();
+  }
+  return (new ValueObjectConstResult(exe_scope, *manager, std::move(error)))
       ->GetSP();
 }
 
diff --git a/lldb/source/ValueObject/ValueObjectConstResultImpl.cpp b/lldb/source/ValueObject/ValueObjectConstResultImpl.cpp
index 874628774d47e..fb0b5e6d09e46 100644
--- a/lldb/source/ValueObject/ValueObjectConstResultImpl.cpp
+++ b/lldb/source/ValueObject/ValueObjectConstResultImpl.cpp
@@ -185,7 +185,7 @@ lldb::ValueObjectSP ValueObjectConstResultImpl::AddressOf(Status &error) {
     m_address_of_backend = ValueObjectConstResult::Create(
         exe_ctx.GetBestExecutionContextScope(), compiler_type.GetPointerType(),
         ConstString(new_name.c_str()), buffer, endian::InlHostByteOrder(),
-        exe_ctx.GetAddressByteSize());
+        exe_ctx.GetAddressByteSize(), LLDB_INVALID_ADDRESS, m_impl_backend->GetManager());
 
     m_address_of_backend->GetValue().SetValueType(Value::ValueType::Scalar);
     m_address_of_backend->GetValue().GetScalar() = m_live_address;
diff --git a/lldb/source/ValueObject/ValueObjectSynthetic.cpp b/lldb/source/ValueObject/ValueObjectSynthetic.cpp
index 595bd67e0b2b6..b81dbea25c820 100644
--- a/lldb/source/ValueObject/ValueObjectSynthetic.cpp
+++ b/lldb/source/ValueObject/ValueObjectSynthetic.cpp
@@ -294,6 +294,9 @@ lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(uint32_t idx,
       }
       synth_guy->SetPreferredDisplayLanguageIfNeeded(
           GetPreferredDisplayLanguage());
+      lldb::ValueObjectSP check_sp = CheckValueObjectOwnership(synth_guy.get());
+      if (check_sp)
+        return check_sp;
       return synth_guy;
     } else {
       LLDB_LOG(log,
@@ -310,7 +313,9 @@ lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(uint32_t idx,
              "[ValueObjectSynthetic::GetChildAtIndex] name={0}, child at "
              "index {1} cached as {2}",
              GetName(), idx, static_cast<void *>(valobj));
-
+    lldb::ValueObjectSP check_sp = CheckValueObjectOwnership(valobj);
+    if (check_sp)
+      return check_sp;
     return valobj->GetSP();
   }
 }
diff --git a/lldb/test/API/commands/expression/issue_11588/Test11588.py b/lldb/test/API/commands/expression/issue_11588/Test11588.py
index 6a059ecb089fb..b4caee36b01cc 100644
--- a/lldb/test/API/commands/expression/issue_11588/Test11588.py
+++ b/lldb/test/API/commands/expression/issue_11588/Test11588.py
@@ -21,7 +21,9 @@ def cleanup():
 
         # Execute the cleanup function during test case tear down.
         self.addTearDownHook(cleanup)
-
+        # This creates a synthetic child with an expression.  Those aren't
+        # properly accounted for yet, so don't check.
+        self.runCmd("settings set target.check-vo-ownership 0")
         """valobj.AddressOf() should return correct values."""
         self.build()
 
diff --git a/lldb/test/API/functionalities/data-formatter/callback-matching/TestDataFormatterCallbackMatching.py b/lldb/test/API/functionalities/data-formatter/callback-matching/TestDataFormatterCallbackMatching.py
index e75925c05909c..4c55fa879c677 100644
--- a/lldb/test/API/functionalities/data-formatter/callback-matching/TestDataFormatterCallbackMatching.py
+++ b/lldb/test/API/functionalities/data-formatter/callback-matching/TestDataFormatterCallbackMatching.py
@@ -14,6 +14,7 @@ def setUp(self):
         TestBase.setUp(self)
         # Find the line number to break at.
         self.line = line_number("main.cpp", "// Set break point at this line.")
+        self.runCmd("settings set target.check-vo-ownership 0")
 
     def test_callback_matchers_api_registration(self):
         """Test data formatter commands."""
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/ftsp.py b/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/ftsp.py
index 4f24a30b9951e..bb64a13bef5d6 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/ftsp.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/ftsp.py
@@ -19,8 +19,10 @@ def get_child_at_index(self, index):
         if index == 0:
             return self.x.Cast(self.char)
         if index == 4:
-            return self.valobj.CreateValueFromExpression(
-                str(index), "(char)(" + str(self.count) + ")"
+            data = lldb.SBData.CreateDataFromInt(self.count)
+            type = self.valobj.target.FindFirstType("char")
+            return self.valobj.CreateValueFromData(
+                str(index), data, type
             )
         return self.x.CreateChildAtOffset(str(index), index, self.char)
 
diff --git a/lldb/test/API/functionalities/data-formatter/type-synth-wants-deref/provider.py b/lldb/test/API/functionalities/data-formatter/type-synth-wants-deref/provider.py
index e4cc5bbc94a22..6c335916d2ea7 100644
--- a/lldb/test/API/functionalities/data-formatter/type-synth-wants-deref/provider.py
+++ b/lldb/test/API/functionalities/data-formatter/type-synth-wants-deref/provider.py
@@ -1,3 +1,5 @@
+import lldb
+
 class WrapperSynthProvider:
     def __init__(self, valobj, internal_dict):
         self.valobj = valobj
@@ -15,7 +17,9 @@ def update(self):
         y = self.valobj.GetChildMemberWithName("y")
         if x.IsValid() and y.IsValid():
             sum_val = x.GetValueAsUnsigned(0) + y.GetValueAsUnsigned(0)
-            self.sum_value = self.valobj.CreateValueFromExpression("sum", str(sum_val))
+            data = lldb.SBData.CreateDataFromInt(sum_val)
+            type = self.valobj.target.FindFirstType("int")
+            self.sum_value = self.valobj.CreateValueFromData("sum", data, type)
 
         return False
 
diff --git a/lldb/test/API/python_api/formatters/synth.py b/lldb/test/API/python_api/formatters/synth.py
index 91afb26af8436..bbeaa18b1a02f 100644
--- a/lldb/test/API/python_api/formatters/synth.py
+++ b/lldb/test/API/python_api/formatters/synth.py
@@ -13,7 +13,10 @@ def get_child_at_index(self, index):
         if index == 0:
             child = self.valobj.GetChildMemberWithName("A")
         if index == 1:
-            child = self.valobj.CreateValueFromExpression("X", "(int)1")
+            import lldb
+            data = lldb.SBData.CreateDataFromInt(1)
+            type = self.valobj.target.FindFirstType("int")
+            child = self.valobj.CreateValueFromData("X", data, type)
         return child
 
     def get_child_index(self, name):



More information about the lldb-commits mailing list