llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Georgiy Samoylov (sga-sc)

<details>
<summary>Changes</summary>

In C, an array name in an expression "decays" into a pointer to its first 
element. LLDB did not honor this: commands like `memory read my_array` did not 
work correctly, because an aggregate type has no scalar value, so trying to 
obtain one (ResolveValue/GetValueAsUnsigned) failed.

This MR adds explicit array decay: for array-typed expressions, the address of 
the array object itself is used instead of its (non-existent) scalar value.

---
Full diff: https://github.com/llvm/llvm-project/pull/210918.diff


3 Files Affected:

- (modified) lldb/source/Interpreter/CommandInterpreter.cpp (+18-1) 
- (modified) lldb/source/Interpreter/OptionArgParser.cpp (+13-2) 
- (modified) lldb/test/API/commands/memory/read/TestMemoryRead.py (+38) 


``````````diff
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp 
b/lldb/source/Interpreter/CommandInterpreter.cpp
index 9887d24112c20..08de320041153 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -51,6 +51,7 @@
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/Telemetry.h"
 #include "lldb/Host/StreamFile.h"
+#include "lldb/Symbol/CompilerType.h"
 #include "lldb/Utility/ErrorMessages.h"
 #include "lldb/Utility/FileSpec.h"
 #include "lldb/Utility/LLDBLog.h"
@@ -59,6 +60,7 @@
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/StructuredData.h"
 #include "lldb/Utility/Timer.h"
+#include "lldb/ValueObject/ValueObject.h"
 
 #include "lldb/Host/Config.h"
 #include "lldb/lldb-forward.h"
@@ -2001,7 +2003,22 @@ Status CommandInterpreter::PreprocessToken(std::string 
&expr_str) {
       expr_result_valobj_sp =
           expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable(
               expr_result_valobj_sp->GetDynamicValueType(), true);
-    if (expr_result_valobj_sp->ResolveValue(scalar)) {
+    // For array-typed results, C decays the array to a pointer to its first
+    // element. ResolveValue() can't produce a scalar for an aggregate, and the
+    // expression evaluator materializes arrays into a temporary result buffer
+    // whose address is not the array's real location. So decay explicitly 
here:
+    // use the address of the array object instead of its (non-existent) scalar
+    // value.
+    if (expr_result_valobj_sp &&
+        expr_result_valobj_sp->GetCompilerType().IsArrayType()) {
+      lldb::addr_t addr =
+          expr_result_valobj_sp->GetAddressOf(/*scalar_is_load_address=*/true)
+              .address;
+      if (addr != LLDB_INVALID_ADDRESS)
+        scalar = addr;
+    }
+
+    if (scalar.IsValid() || expr_result_valobj_sp->ResolveValue(scalar)) {
 
       StreamString value_strm;
       const bool show_type = false;
diff --git a/lldb/source/Interpreter/OptionArgParser.cpp 
b/lldb/source/Interpreter/OptionArgParser.cpp
index 170f65ad80a74..bdbf9859faa09 100644
--- a/lldb/source/Interpreter/OptionArgParser.cpp
+++ b/lldb/source/Interpreter/OptionArgParser.cpp
@@ -8,6 +8,7 @@
 
 #include "lldb/Interpreter/OptionArgParser.h"
 #include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Symbol/CompilerType.h"
 #include "lldb/Target/ABI.h"
 #include "lldb/Target/RegisterContext.h"
 #include "lldb/Target/Target.h"
@@ -231,8 +232,18 @@ OptionArgParser::DoToAddress(const ExecutionContext 
*exe_ctx, llvm::StringRef s,
       valobj_sp = valobj_sp->GetQualifiedRepresentationIfAvailable(
           valobj_sp->GetDynamicValueType(), true);
     // Get the address to watch.
-    if (valobj_sp)
-      addr = valobj_sp->GetValueAsUnsigned(0, &success);
+    if (valobj_sp) {
+      // In C an array decays to a pointer to its first element, whose value is
+      // the address of the array object itself. An aggregate has no scalar
+      // value, so GetValueAsUnsigned() would fail here; use the array's own
+      // load address instead.
+      if (valobj_sp->GetCompilerType().IsArrayType()) {
+        addr = 
valobj_sp->GetAddressOf(/*scalar_is_load_address=*/true).address;
+        success = addr != LLDB_INVALID_ADDRESS;
+      } else {
+        addr = valobj_sp->GetValueAsUnsigned(0, &success);
+      }
+    }
     if (success) {
       if (error_ptr)
         error_ptr->Clear();
diff --git a/lldb/test/API/commands/memory/read/TestMemoryRead.py 
b/lldb/test/API/commands/memory/read/TestMemoryRead.py
index bc8c45a402423..2a3268f38e600 100644
--- a/lldb/test/API/commands/memory/read/TestMemoryRead.py
+++ b/lldb/test/API/commands/memory/read/TestMemoryRead.py
@@ -144,6 +144,44 @@ def test_memory_read(self):
                 self.assertEqual(len(o), expected_object_length)
             self.assertEqual(len(objects_read), 4)
 
+    def test_memory_read_array_name_decays_to_address(self):
+        """An array expression decays to a pointer to its first element, so
+        `memory read <array>` and `memory read `<array>`` must behave like
+        `memory read &<array>`, rather than failing or reading a bogus 
address."""
+        self.build_run_stop()
+
+        fmt = "memory read --format uint32_t[] --size 4 --count 3 "
+
+        def read_addr_and_values(suffix):
+            self.runCmd(fmt + suffix)
+            lines = self.res.GetOutput().splitlines()
+            addr = int(lines[0].split(":")[0], 0)
+            values = []
+            for line in lines:
+                values.extend(v.strip(" {}") for v in 
line.split(":")[1].split())
+            return addr, values
+
+        # Taking the address explicitly yields a pointer whose value is the
+        # array's address; this is the reference every other form must match.
+        ref_addr, ref_values = read_addr_and_values("&my_ints")
+        self.assertEqual(
+            ref_values, ["0x00000002", "0x00000004", "0x00000006"]
+        )
+
+        # Every one of these forms must resolve to the same address and data:
+        #   &my_ints        pointer, via OptionArgParser::ToAddress
+        #   `&my_ints`      pointer, via CommandInterpreter::PreprocessToken
+        #   my_ints         array decay, via OptionArgParser::ToAddress
+        #   `my_ints`       array decay, via 
CommandInterpreter::PreprocessToken
+        for suffix in ["&my_ints", "`&my_ints`", "my_ints", "`my_ints`"]:
+            addr, values = read_addr_and_values(suffix)
+            self.assertEqual(
+                addr, ref_addr, "wrong address for 'memory read %s'" % suffix
+            )
+            self.assertEqual(
+                values, ref_values, "wrong data for 'memory read %s'" % suffix
+            )
+
     def test_memory_read_file(self):
         self.build_run_stop()
         res = lldb.SBCommandReturnObject()

``````````

</details>


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

Reply via email to