[Lldb-commits] [lldb] r179857 - Provided a variant of ReadCStringFromMemory that supports null terminators of any character width.

Ashok Thirumurthi ashok.thirumurthi at intel.com
Fri Apr 19 08:58:38 PDT 2013


Author: athirumu
Date: Fri Apr 19 10:58:38 2013
New Revision: 179857

URL: http://llvm.org/viewvc/llvm-project?rev=179857&view=rev
Log:
Provided a variant of ReadCStringFromMemory that supports null terminators of any character width.
This prevents unbounded reads (i.e. reads of GetMaximumSizeOfStringSummary() bytes)
from causing test failures (i.e. due to ptrace EIO or EFAULT on Linux).

Note that ReadCStringFromMemory is marked as deprecated because the loop that calls
ReadMemory does not continue until the string has been completely read.
The expected behavior is to read until until max_bytes or a null terminator.

Note: As discussed on lldb-dev, further testing will be performed with ReadStringFromMemory
before further changes are made for users of ReadCStringFromMemory.

Thanks to Enrico, Matt and Andy for their review feedback.

Modified:
    lldb/trunk/include/lldb/Target/Process.h
    lldb/trunk/source/DataFormatters/CXXFormatterFunctions.cpp
    lldb/trunk/source/Target/Process.cpp
    lldb/trunk/test/lang/cpp/char1632_t/TestChar1632T.py
    lldb/trunk/test/lang/cpp/wchar_t/TestCxxWCharT.py

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=179857&r1=179856&r2=179857&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Fri Apr 19 10:58:38 2013
@@ -2682,6 +2682,42 @@ public:
                 Error &error);
 
     //------------------------------------------------------------------
+    /// Read a NULL terminated string from memory
+    ///
+    /// This function will read a cache page at a time until a NULL
+    /// string terminator is found. It will stop reading if an aligned
+    /// sequence of NULL termination \a type_width bytes is not found
+    /// before reading \a cstr_max_len bytes.  The results are always 
+    /// guaranteed to be NULL terminated, and that no more than
+    /// (max_bytes - type_width) bytes will be read.
+    ///
+    /// @param[in] vm_addr
+    ///     The virtual load address to start the memory read.
+    ///
+    /// @param[in] str
+    ///     A character buffer containing at least max_bytes.
+    ///
+    /// @param[in] max_bytes
+    ///     The maximum number of bytes to read.
+    ///
+    /// @param[in] error
+    ///     The error status of the read operation.
+    ///
+    /// @param[in] type_width
+    ///     The size of the null terminator (1 to 4 bytes per
+    ///     character).  Defaults to 1.
+    ///
+    /// @return
+    ///     The error status or the number of bytes prior to the null terminator.
+    //------------------------------------------------------------------
+    size_t
+    ReadStringFromMemory (lldb::addr_t vm_addr, 
+                           char *str, 
+                           size_t max_bytes,
+                           Error &error,
+                           size_t type_width = 1);
+
+    //------------------------------------------------------------------
     /// Read a NULL terminated C string from memory
     ///
     /// This function will read a cache page at a time until the NULL

Modified: lldb/trunk/source/DataFormatters/CXXFormatterFunctions.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/DataFormatters/CXXFormatterFunctions.cpp?rev=179857&r1=179856&r2=179857&view=diff
==============================================================================
--- lldb/trunk/source/DataFormatters/CXXFormatterFunctions.cpp (original)
+++ lldb/trunk/source/DataFormatters/CXXFormatterFunctions.cpp Fri Apr 19 10:58:38 2013
@@ -264,7 +264,8 @@ ReadUTFBufferAndDumpToStream (Conversion
     if (!process_sp)
         return false;
 
-    const int origin_encoding = 8*sizeof(SourceDataType);
+    const int type_width = sizeof(SourceDataType);
+    const int origin_encoding = 8 * type_width ;
     if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32)
         return false;
     // if not UTF8, I need a conversion function to return proper UTF8
@@ -276,15 +277,17 @@ ReadUTFBufferAndDumpToStream (Conversion
     else
         sourceSize = std::min(sourceSize,process_sp->GetTarget().GetMaximumSizeOfStringSummary());
     
-    const int bufferSPSize = sourceSize * (origin_encoding >> 2);
+    const int bufferSPSize = sourceSize * type_width;
 
-    Error error;
     lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0));
     
     if (!buffer_sp->GetBytes())
         return false;
     
-    size_t data_read = process_sp->ReadMemoryFromInferior(location, (char*)buffer_sp->GetBytes(), bufferSPSize, error);
+    Error error;
+    char *buffer = reinterpret_cast<char *>(buffer_sp->GetBytes()); 
+
+    size_t data_read = process_sp->ReadStringFromMemory(location, buffer, bufferSPSize, error, type_width);
     if (error.Fail() || data_read == 0)
     {
         stream.Printf("unable to read data");

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=179857&r1=179856&r2=179857&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Fri Apr 19 10:58:38 2013
@@ -2357,6 +2357,60 @@ Process::ReadCStringFromMemory (addr_t a
 
 
 size_t
+Process::ReadStringFromMemory (addr_t addr, char *dst, size_t max_bytes, Error &error,
+                                size_t type_width)
+{
+    size_t total_bytes_read = 0;
+    if (dst && max_bytes && type_width && max_bytes >= type_width)
+    {
+        // Ensure a null terminator independent of the number of bytes that is read.
+        memset (dst, 0, max_bytes);
+        size_t bytes_left = max_bytes - type_width;
+
+        const char terminator[4] = {'\0', '\0', '\0', '\0'};
+        assert(sizeof(terminator) >= type_width &&
+               "Attempting to validate a string with more than 4 bytes per character!");
+
+        addr_t curr_addr = addr;
+        const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize();
+        char *curr_dst = dst;
+
+        error.Clear();
+        while (bytes_left > 0 && error.Success())
+        {
+            addr_t cache_line_bytes_left = cache_line_size - (curr_addr % cache_line_size);
+            addr_t bytes_to_read = std::min<addr_t>(bytes_left, cache_line_bytes_left);
+            size_t bytes_read = ReadMemory (curr_addr, curr_dst, bytes_to_read, error);
+
+            if (bytes_read == 0)
+                break;
+
+            // Search for a null terminator of correct size and alignment in bytes_read
+            size_t aligned_start = total_bytes_read - total_bytes_read % type_width;
+            for (size_t i = aligned_start; i + type_width <= total_bytes_read + bytes_read; i += type_width)
+                if (::strncmp(&dst[i], terminator, type_width) == 0)
+                {
+                    error.Clear();
+                    return i;
+                }
+
+            total_bytes_read += bytes_read;
+            curr_dst += bytes_read;
+            curr_addr += bytes_read;
+            bytes_left -= bytes_read;
+        }
+    }
+    else
+    {
+        if (max_bytes)
+            error.SetErrorString("invalid arguments");
+    }
+    return total_bytes_read;
+}
+
+// Deprecated in favor of ReadStringFromMemory which has wchar support and correct code to find
+// null terminators.
+size_t
 Process::ReadCStringFromMemory (addr_t addr, char *dst, size_t dst_max_len, Error &result_error)
 {
     size_t total_cstr_len = 0;

Modified: lldb/trunk/test/lang/cpp/char1632_t/TestChar1632T.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/cpp/char1632_t/TestChar1632T.py?rev=179857&r1=179856&r2=179857&view=diff
==============================================================================
--- lldb/trunk/test/lang/cpp/char1632_t/TestChar1632T.py (original)
+++ lldb/trunk/test/lang/cpp/char1632_t/TestChar1632T.py Fri Apr 19 10:58:38 2013
@@ -20,7 +20,6 @@ class Char1632TestCase(TestBase):
         self.buildDsym()
         self.char1632()
 
-    @expectedFailureLinux # bugzilla 15038: missing wide char support on Linux
     @dwarf_test
     def test_with_dwarf(self):
         """Test that the C++11 support for char16_t and char32_t works correctly."""

Modified: lldb/trunk/test/lang/cpp/wchar_t/TestCxxWCharT.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/cpp/wchar_t/TestCxxWCharT.py?rev=179857&r1=179856&r2=179857&view=diff
==============================================================================
--- lldb/trunk/test/lang/cpp/wchar_t/TestCxxWCharT.py (original)
+++ lldb/trunk/test/lang/cpp/wchar_t/TestCxxWCharT.py Fri Apr 19 10:58:38 2013
@@ -20,7 +20,6 @@ class CxxWCharTTestCase(TestBase):
         self.buildDsym()
         self.wchar_t()
 
-    @expectedFailureLinux # bugzilla 15038: missing wide char support on Linux
     @dwarf_test
     def test_with_dwarf(self):
         """Test that C++ supports wchar_t correctly."""





More information about the lldb-commits mailing list