Don't allow SBValue::Cast to cast from a smaller type to a larger,
authorJim Ingham <jingham@apple.com>
Mon, 26 Jun 2023 23:01:18 +0000 (16:01 -0700)
committerJim Ingham <jingham@apple.com>
Mon, 26 Jun 2023 23:02:01 +0000 (16:02 -0700)
as we don't in general know where the extra data should come from.

Differential Revision: https://reviews.llvm.org/D153657

13 files changed:
lldb/include/lldb/Core/ValueObject.h
lldb/include/lldb/Core/ValueObjectConstResult.h
lldb/include/lldb/Core/ValueObjectConstResultCast.h
lldb/include/lldb/Core/ValueObjectConstResultChild.h
lldb/packages/Python/lldbsuite/test/lldbtest.py
lldb/source/Core/ValueObject.cpp
lldb/source/Core/ValueObjectConstResult.cpp
lldb/source/Core/ValueObjectConstResultCast.cpp
lldb/source/Core/ValueObjectConstResultChild.cpp
lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
lldb/test/API/python_api/value/TestValueAPI.py
lldb/test/API/python_api/value/main.c

index 2f2b212..2d8036a 100644 (file)
@@ -614,7 +614,9 @@ public:
   virtual void SetLiveAddress(lldb::addr_t addr = LLDB_INVALID_ADDRESS,
                               AddressType address_type = eAddressTypeLoad) {}
 
-  virtual lldb::ValueObjectSP Cast(const CompilerType &compiler_type);
+  lldb::ValueObjectSP Cast(const CompilerType &compiler_type);
+
+  virtual lldb::ValueObjectSP DoCast(const CompilerType &compiler_type);
 
   virtual lldb::ValueObjectSP CastPointerType(const char *name,
                                               CompilerType &ast_type);
index 4edd495..d61df85 100644 (file)
@@ -106,7 +106,7 @@ public:
 
   lldb::LanguageType GetPreferredDisplayLanguage() override;
 
-  lldb::ValueObjectSP Cast(const CompilerType &compiler_type) override;
+  lldb::ValueObjectSP DoCast(const CompilerType &compiler_type) override;
 
 protected:
   bool UpdateValue() override;
index 5467ce3..efcbe0d 100644 (file)
@@ -51,7 +51,7 @@ public:
   size_t GetPointeeData(DataExtractor &data, uint32_t item_idx = 0,
                         uint32_t item_count = 1) override;
 
-  lldb::ValueObjectSP Cast(const CompilerType &compiler_type) override;
+  lldb::ValueObjectSP DoCast(const CompilerType &compiler_type) override;
 
 protected:
   ValueObjectConstResultImpl m_impl;
index 26bd9f3..7e9da14 100644 (file)
@@ -60,7 +60,7 @@ public:
   size_t GetPointeeData(DataExtractor &data, uint32_t item_idx = 0,
                         uint32_t item_count = 1) override;
 
-  lldb::ValueObjectSP Cast(const CompilerType &compiler_type) override;
+  lldb::ValueObjectSP DoCast(const CompilerType &compiler_type) override;
 
 protected:
   ValueObjectConstResultImpl m_impl;
index a712f6b..2bff1a7 100644 (file)
@@ -2604,6 +2604,17 @@ FileCheck output:
         if not obj.Success():
             error = obj.GetCString()
             self.fail(self._formatMessage(msg, "'{}' is not success".format(error)))
+    """Assert that an lldb.SBError is in the "failure" state."""
+
+    def assertFailure(self, obj, error_str = None, msg=None):
+        if obj.Success():
+            self.fail(self._formatMessage(msg, "Error not in a fail state"))
+
+        if error_str == None:
+            return
+                      
+        error = obj.GetCString()
+        self.assertEqual(error, error_str, msg)
 
     """Assert that a command return object is successful"""
 
index 9ff980d..d60a1d6 100644 (file)
@@ -2779,8 +2779,30 @@ ValueObjectSP ValueObject::AddressOf(Status &error) {
   return m_addr_of_valobj_sp;
 }
 
+ValueObjectSP ValueObject::DoCast(const CompilerType &compiler_type) {
+    return ValueObjectCast::Create(*this, GetName(), compiler_type);
+}
+
 ValueObjectSP ValueObject::Cast(const CompilerType &compiler_type) {
-  return ValueObjectCast::Create(*this, GetName(), compiler_type);
+  // Only allow casts if the original type is equal or larger than the cast
+  // type.  We don't know how to fetch more data for all the ConstResult types, 
+  // so we can't guarantee this will work:
+  Status error;
+  CompilerType my_type = GetCompilerType();
+
+  ExecutionContextScope *exe_scope 
+      = ExecutionContext(GetExecutionContextRef())
+          .GetBestExecutionContextScope();
+  if (compiler_type.GetByteSize(exe_scope) 
+      <= GetCompilerType().GetByteSize(exe_scope)) {
+        return DoCast(compiler_type);
+  }
+  error.SetErrorString("Can only cast to a type that is equal to or smaller "
+                       "than the orignal type.");
+
+  return ValueObjectConstResult::Create(
+      ExecutionContext(GetExecutionContextRef()).GetBestExecutionContextScope(),
+                       error);
 }
 
 lldb::ValueObjectSP ValueObject::Clone(ConstString new_name) {
index 17a725d..693da1a 100644 (file)
@@ -294,7 +294,7 @@ ValueObjectConstResult::GetDynamicValue(lldb::DynamicValueType use_dynamic) {
 }
 
 lldb::ValueObjectSP
-ValueObjectConstResult::Cast(const CompilerType &compiler_type) {
+ValueObjectConstResult::DoCast(const CompilerType &compiler_type) {
   return m_impl.Cast(compiler_type);
 }
 
index e70d055..fceb263 100644 (file)
@@ -57,6 +57,6 @@ size_t ValueObjectConstResultCast::GetPointeeData(DataExtractor &data,
 }
 
 lldb::ValueObjectSP
-ValueObjectConstResultCast::Cast(const CompilerType &compiler_type) {
+ValueObjectConstResultCast::DoCast(const CompilerType &compiler_type) {
   return m_impl.Cast(compiler_type);
 }
index 0fd8141..36bf11a 100644 (file)
@@ -69,6 +69,6 @@ size_t ValueObjectConstResultChild::GetPointeeData(DataExtractor &data,
 }
 
 lldb::ValueObjectSP
-ValueObjectConstResultChild::Cast(const CompilerType &compiler_type) {
+ValueObjectConstResultChild::DoCast(const CompilerType &compiler_type) {
   return m_impl.Cast(compiler_type);
 }
index 666b467..de4f23b 100644 (file)
@@ -607,11 +607,13 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex(
   if (idx == 1) {
     if (auto ptr_sp = valobj_sp->GetChildMemberWithName("__ptr_")) {
       Status status;
-      auto value_sp = ptr_sp->Dereference(status);
+      auto value_type_sp =
+            valobj_sp->GetCompilerType()
+              .GetTypeTemplateArgument(0).GetPointerType();
+      ValueObjectSP cast_ptr_sp = ptr_sp->Cast(value_type_sp);
+      ValueObjectSP value_sp = cast_ptr_sp->Dereference(status);
       if (status.Success()) {
-        auto value_type_sp =
-            valobj_sp->GetCompilerType().GetTypeTemplateArgument(0);
-        return value_sp->Cast(value_type_sp);
+        return value_sp;
       }
     }
   }
index 50e8650..14776cd 100644 (file)
@@ -157,7 +157,11 @@ lldb::ValueObjectSP lldb_private::formatters::
       }
       if (!m_node_type)
         return nullptr;
-      node_sp = node_sp->Cast(m_node_type);
+      node_sp = m_next_element->Cast(m_node_type.GetPointerType())
+              ->Dereference(error);
+      if (!node_sp || error.Fail())
+          return nullptr;
+
       value_sp = node_sp->GetChildMemberWithName("__value_");
       hash_sp = node_sp->GetChildMemberWithName("__hash_");
       if (!value_sp || !hash_sp)
index dc68eb6..b5d065e 100644 (file)
@@ -146,6 +146,19 @@ class ValueAPITestCase(TestBase):
         self.assertTrue(val_s.GetChildMemberWithName("a").AddressOf(), VALID_VARIABLE)
         self.assertTrue(val_a.Cast(val_i.GetType()).AddressOf(), VALID_VARIABLE)
 
+        # Test some other cases of the Cast API.  We allow casts from one struct type
+        # to another, which is a little weird, but we don't support casting from a
+        # smaller type to a larger as we often wouldn't know how to get the extra data:
+        val_f = target.EvaluateExpression("f")
+        bad_cast = val_s.Cast(val_f.GetType())
+        self.assertFailure(bad_cast.GetError(),
+                           "Can only cast to a type that is equal to or smaller than the orignal type.")
+        weird_cast = val_f.Cast(val_s.GetType())
+        self.assertSuccess(weird_cast.GetError(),
+                        "Can cast from a larger to a smaller")
+        self.assertEqual(weird_cast.GetChildMemberWithName("a").GetValueAsSigned(0), 33,
+                         "Got the right value")
+
         # Check that lldb.value implements truth testing.
         self.assertFalse(lldb.value(frame0.FindVariable("bogus")))
         self.assertTrue(lldb.value(frame0.FindVariable("uinthex")))
index c2e0dc8..bf00aba 100644 (file)
@@ -29,6 +29,13 @@ struct MyStruct
   int b;
 };
 
+struct MyBiggerStruct
+{
+  int a;
+  int b;
+  int c;
+};
+
 int main (int argc, char const *argv[])
 {
     uint32_t uinthex = 0xE0A35F10;
@@ -37,6 +44,7 @@ int main (int argc, char const *argv[])
     int i;
     MyInt a = 12345;
     struct MyStruct s = { 11, 22 };
+    struct MyBiggerStruct f = { 33, 44, 55 }; 
     int *my_int_ptr = &g_my_int;
     printf("my_int_ptr points to location %p\n", my_int_ptr);
     const char **str_ptr = days_of_week;