jingham created this revision.
jingham added reviewers: JDevlieghere, kastiglione, mib.
Herald added a project: All.
jingham requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

SBValue::Cast actually allows casting from a struct type to another struct 
type.  That's a little odd, C-family languages don't allow this, but we have 
done forever, so I don't want to remove the ability altogether.  However, we 
can't support casting from a small structure to a larger one because in some 
cases - e.g. all the ConstResult types used both for expression results and for 
many synthetic children - we don't know where we should fetch the extra bits 
from.  Just zero-filling them seems odd, and error seems like a better response.

This fixes a bug where when casting an expression result from a smaller type to 
a larger, lldb would present the memory in lldb after the ValueObject's data 
buffer as the value of the cast type.  Again, I could have fixed that bug by 
expanding the data buffer to match the larger size, but I wouldn't know what to 
fill it with.

There were two places in the C++ formatters that were using this cast from 
struct to struct type to change a C++ std typedef (e.g. 
std::shared_ptr<Foo>::element type *) to a type that is more useful to the user 
(pointer to the first template argument's type).  The cast from struct to 
struct in that case wasn't necessary, and looked weird since this really isn't 
an allowed C++ operation.  So I also changed those to case the pointer first, 
then dereference the cast value.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D153657

Files:
  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: lldb/test/API/python_api/value/main.c
===================================================================
--- lldb/test/API/python_api/value/main.c
+++ lldb/test/API/python_api/value/main.c
@@ -29,6 +29,13 @@
   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 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;
Index: lldb/test/API/python_api/value/TestValueAPI.py
===================================================================
--- lldb/test/API/python_api/value/TestValueAPI.py
+++ lldb/test/API/python_api/value/TestValueAPI.py
@@ -146,6 +146,19 @@
         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: lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
===================================================================
--- lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
+++ lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -157,7 +157,11 @@
       }
       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: lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
===================================================================
--- lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -607,11 +607,13 @@
   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: lldb/source/Core/ValueObjectConstResultChild.cpp
===================================================================
--- lldb/source/Core/ValueObjectConstResultChild.cpp
+++ lldb/source/Core/ValueObjectConstResultChild.cpp
@@ -69,6 +69,6 @@
 }
 
 lldb::ValueObjectSP
-ValueObjectConstResultChild::Cast(const CompilerType &compiler_type) {
+ValueObjectConstResultChild::DoCast(const CompilerType &compiler_type) {
   return m_impl.Cast(compiler_type);
 }
Index: lldb/source/Core/ValueObjectConstResultCast.cpp
===================================================================
--- lldb/source/Core/ValueObjectConstResultCast.cpp
+++ lldb/source/Core/ValueObjectConstResultCast.cpp
@@ -57,6 +57,6 @@
 }
 
 lldb::ValueObjectSP
-ValueObjectConstResultCast::Cast(const CompilerType &compiler_type) {
+ValueObjectConstResultCast::DoCast(const CompilerType &compiler_type) {
   return m_impl.Cast(compiler_type);
 }
Index: lldb/source/Core/ValueObjectConstResult.cpp
===================================================================
--- lldb/source/Core/ValueObjectConstResult.cpp
+++ lldb/source/Core/ValueObjectConstResult.cpp
@@ -294,7 +294,7 @@
 }
 
 lldb::ValueObjectSP
-ValueObjectConstResult::Cast(const CompilerType &compiler_type) {
+ValueObjectConstResult::DoCast(const CompilerType &compiler_type) {
   return m_impl.Cast(compiler_type);
 }
 
Index: lldb/source/Core/ValueObject.cpp
===================================================================
--- lldb/source/Core/ValueObject.cpp
+++ lldb/source/Core/ValueObject.cpp
@@ -2779,8 +2779,31 @@
   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();
+  bool unused;
+
+  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: lldb/packages/Python/lldbsuite/test/lldbtest.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -2604,6 +2604,17 @@
         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: lldb/include/lldb/Core/ValueObjectConstResultChild.h
===================================================================
--- lldb/include/lldb/Core/ValueObjectConstResultChild.h
+++ lldb/include/lldb/Core/ValueObjectConstResultChild.h
@@ -60,7 +60,7 @@
   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: lldb/include/lldb/Core/ValueObjectConstResultCast.h
===================================================================
--- lldb/include/lldb/Core/ValueObjectConstResultCast.h
+++ lldb/include/lldb/Core/ValueObjectConstResultCast.h
@@ -51,7 +51,7 @@
   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: lldb/include/lldb/Core/ValueObjectConstResult.h
===================================================================
--- lldb/include/lldb/Core/ValueObjectConstResult.h
+++ lldb/include/lldb/Core/ValueObjectConstResult.h
@@ -106,7 +106,7 @@
 
   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: lldb/include/lldb/Core/ValueObject.h
===================================================================
--- lldb/include/lldb/Core/ValueObject.h
+++ lldb/include/lldb/Core/ValueObject.h
@@ -614,7 +614,9 @@
   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);
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to