Teach the NSString data formatter to handle embedded NULs in short ASCII strings

llvm-svn: 242559
diff --git a/lldb/source/DataFormatters/CXXFormatterFunctions.cpp b/lldb/source/DataFormatters/CXXFormatterFunctions.cpp
index e845d64..d3c6f8e 100644
--- a/lldb/source/DataFormatters/CXXFormatterFunctions.cpp
+++ b/lldb/source/DataFormatters/CXXFormatterFunctions.cpp
@@ -1008,15 +1008,30 @@
     {
         uint64_t location = valobj_addr + 2*ptr_size;
         if (!has_explicit_length)
+        {
+            // in this kind of string, the byte before the string content is a length byte
+            // so let's try and use it to handle the embedded NUL case
+            Error error;
+            explicit_length = process_sp->ReadUnsignedIntegerFromMemory(location, 1, 0, error);
+            if (error.Fail() || explicit_length == 0)
+                has_explicit_length = false;
+            else
+                has_explicit_length = true;
             location++;
+        }
         ReadStringAndDumpToStreamOptions options(valobj);
         options.SetLocation(location);
         options.SetProcessSP(process_sp);
         options.SetStream(&stream);
         options.SetPrefixToken('@');
         options.SetSourceSize(explicit_length);
+        options.SetNeedsZeroTermination(!has_explicit_length);
         options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
-        return ReadStringAndDumpToStream<StringElementType::ASCII>(options);
+        options.SetBinaryZeroIsTerminator(!has_explicit_length);
+        if (has_explicit_length)
+            return ReadStringAndDumpToStream<StringElementType::UTF8>(options);
+        else
+            return ReadStringAndDumpToStream<StringElementType::ASCII>(options);
     }
     else
     {
diff --git a/lldb/test/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py b/lldb/test/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py
index 73f9f5f..563ba5a 100644
--- a/lldb/test/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py
+++ b/lldb/test/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py
@@ -63,6 +63,19 @@
         """Check that Unicode characters come out of CFString summary correctly."""
         self.appkit_tester_impl(self.buildDwarf,self.rdar11106605_commands)
 
+    @skipUnlessDarwin
+    @dsym_test
+    def test_nsstring_withNULs_with_dsym_and_run_command(self):
+        """Test formatters for NSString."""
+        self.appkit_tester_impl(self.buildDsym,self.nsstring_withNULs_commands)
+
+    @skipUnlessDarwin
+    @dwarf_test
+    def test_nsstring_withNULS_with_dwarf_and_run_command(self):
+        """Test formatters for NSString."""
+        self.appkit_tester_impl(self.buildDwarf,self.nsstring_withNULs_commands)
+
+
     def setUp(self):
         # Call super's setUp().
         TestBase.setUp(self)
@@ -102,9 +115,15 @@
         self.expect('expr -d run-target -- path',substrs = ['usr/blah/stuff'])
         self.expect('frame variable path',substrs = ['usr/blah/stuff'])
 
+    def nsstring_withNULs_commands(self):
+        """Check that the NSString formatter supports embedded NULs in the text"""
         self.expect('po strwithNULs', substrs=['a very much boring task to write'])
         self.expect('expr [strwithNULs length]', substrs=['54'])
         self.expect('frame variable strwithNULs', substrs=['@"a very much boring task to write\\0a string this way!!'])
+        self.expect('po strwithNULs2', substrs=['a very much boring task to write'])
+        self.expect('expr [strwithNULs2 length]', substrs=['52'])
+        self.expect('frame variable strwithNULs2', substrs=['@"a very much boring task to write\\0a string this way!!'])
+
 
 if __name__ == '__main__':
     import atexit
diff --git a/lldb/test/functionalities/data-formatter/data-formatter-objc/nsstring/main.m b/lldb/test/functionalities/data-formatter/data-formatter-objc/nsstring/main.m
index 14b9200..7b8c378 100644
--- a/lldb/test/functionalities/data-formatter/data-formatter-objc/nsstring/main.m
+++ b/lldb/test/functionalities/data-formatter/data-formatter-objc/nsstring/main.m
@@ -86,6 +86,13 @@
   NSString *strwithNULs = [NSString stringWithCharacters: someOfTheseAreNUL
                                            length: sizeof someOfTheseAreNUL / sizeof *someOfTheseAreNUL];
 
+  const unichar someOfTheseAreNUL2[] = {'a',' ', 'v','e','r','y',' ',
+      'm','u','c','h',' ','b','o','r','i','n','g',' ','t','a','s','k',
+      ' ','t','o',' ','w','r','i','t','e', 0, 'a', ' ', 's', 't', 'r', 'i', 'n', 'g', ' ',
+      't','h','i','s',' ','w','a','y','!','!'};
+  NSString *strwithNULs2 = [NSString stringWithCharacters: someOfTheseAreNUL2
+                                           length: sizeof someOfTheseAreNUL2 / sizeof *someOfTheseAreNUL2];
+
     [pool drain]; // break here
     return 0;
 }