Add StringPrinter support for printing a std::string with embedded NUL bytes
authorEnrico Granata <egranata@apple.com>
Fri, 17 Jul 2015 01:03:59 +0000 (01:03 +0000)
committerEnrico Granata <egranata@apple.com>
Fri, 17 Jul 2015 01:03:59 +0000 (01:03 +0000)
llvm-svn: 242496

lldb/include/lldb/DataFormatters/StringPrinter.h
lldb/source/DataFormatters/CXXFormatterFunctions.cpp
lldb/source/DataFormatters/StringPrinter.cpp
lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py
lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp

index 48e27ac..a41a2ae 100644 (file)
@@ -38,7 +38,8 @@ namespace lldb_private {
             m_source_size(0),
             m_needs_zero_termination(true),
             m_escape_non_printables(true),
-            m_ignore_max_length(false)
+            m_ignore_max_length(false),
+            m_zero_is_terminator(true)
             {
             }
             
@@ -136,6 +137,19 @@ namespace lldb_private {
             }
             
             ReadStringAndDumpToStreamOptions&
+            SetBinaryZeroIsTerminator (bool e)
+            {
+                m_zero_is_terminator = e;
+                return *this;
+            }
+            
+            bool
+            GetBinaryZeroIsTerminator () const
+            {
+                return m_zero_is_terminator;
+            }
+            
+            ReadStringAndDumpToStreamOptions&
             SetEscapeNonPrintables (bool e)
             {
                 m_escape_non_printables = e;
@@ -171,6 +185,7 @@ namespace lldb_private {
             bool m_needs_zero_termination;
             bool m_escape_non_printables;
             bool m_ignore_max_length;
+            bool m_zero_is_terminator;
         };
         
         class ReadBufferAndDumpToStreamOptions
@@ -183,12 +198,15 @@ namespace lldb_private {
             m_prefix_token(0),
             m_quote('"'),
             m_source_size(0),
-            m_escape_non_printables(true)
+            m_escape_non_printables(true),
+            m_zero_is_terminator(true)
             {
             }
             
             ReadBufferAndDumpToStreamOptions (ValueObject& valobj);
             
+            ReadBufferAndDumpToStreamOptions (const ReadStringAndDumpToStreamOptions& options);
+            
             ReadBufferAndDumpToStreamOptions&
             SetData (DataExtractor d)
             {
@@ -267,6 +285,19 @@ namespace lldb_private {
                 return m_escape_non_printables;
             }
             
+            ReadBufferAndDumpToStreamOptions&
+            SetBinaryZeroIsTerminator (bool e)
+            {
+                m_zero_is_terminator = e;
+                return *this;
+            }
+            
+            bool
+            GetBinaryZeroIsTerminator () const
+            {
+                return m_zero_is_terminator;
+            }
+            
         private:
             DataExtractor m_data;
             Stream* m_stream;
@@ -274,15 +305,16 @@ namespace lldb_private {
             char m_quote;
             uint32_t m_source_size;
             bool m_escape_non_printables;
+            bool m_zero_is_terminator;
         };
         
         template <StringElementType element_type>
         bool
-        ReadStringAndDumpToStream (ReadStringAndDumpToStreamOptions options);
+        ReadStringAndDumpToStream (const ReadStringAndDumpToStreamOptions& options);
         
         template <StringElementType element_type>
         bool
-        ReadBufferAndDumpToStream (ReadBufferAndDumpToStreamOptions options);
+        ReadBufferAndDumpToStream (const ReadBufferAndDumpToStreamOptions& options);
         
     } // namespace formatters
 } // namespace lldb_private
index 49eacee..9c59ea1 100644 (file)
@@ -539,6 +539,7 @@ lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stre
     options.SetPrefixToken(0);
     options.SetQuote('"');
     options.SetSourceSize(size);
+    options.SetBinaryZeroIsTerminator(false);
     lldb_private::formatters::ReadBufferAndDumpToStream<lldb_private::formatters::StringElementType::ASCII>(options);
     
     return true;
index a011cd5..60c246f 100644 (file)
@@ -334,41 +334,44 @@ DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType
                                                             UTF8**,
                                                             UTF8*,
                                                             ConversionFlags),
-                       const DataExtractor& data,
-                       Stream& stream,
-                       char prefix_token,
-                       char quote,
-                       uint32_t sourceSize,
-                       bool escapeNonPrintables)
+                       const ReadBufferAndDumpToStreamOptions& dump_options)
 {
-    if (prefix_token != 0)
-        stream.Printf("%c",prefix_token);
-    if (quote != 0)
-        stream.Printf("%c",quote);
+    Stream &stream(*dump_options.GetStream());
+    if (dump_options.GetPrefixToken() != 0)
+        stream.Printf("%c",dump_options.GetPrefixToken());
+    if (dump_options.GetQuote() != 0)
+        stream.Printf("%c",dump_options.GetQuote());
+    auto data(dump_options.GetData());
+    auto source_size(dump_options.GetSourceSize());
     if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd())
     {
         const int bufferSPSize = data.GetByteSize();
-        if (sourceSize == 0)
+        if (dump_options.GetSourceSize() == 0)
         {
             const int origin_encoding = 8*sizeof(SourceDataType);
-            sourceSize = bufferSPSize/(origin_encoding / 4);
+            source_size = bufferSPSize/(origin_encoding / 4);
         }
         
         const SourceDataType *data_ptr = (const SourceDataType*)data.GetDataStart();
-        const SourceDataType *data_end_ptr = data_ptr + sourceSize;
+        const SourceDataType *data_end_ptr = data_ptr + source_size;
         
-        while (data_ptr < data_end_ptr)
+        const bool zero_is_terminator = dump_options.GetBinaryZeroIsTerminator();
+        
+        if (zero_is_terminator)
         {
-            if (!*data_ptr)
+            while (data_ptr < data_end_ptr)
             {
-                data_end_ptr = data_ptr;
-                break;
+                if (!*data_ptr)
+                {
+                    data_end_ptr = data_ptr;
+                    break;
+                }
+                data_ptr++;
             }
-            data_ptr++;
+            
+            data_ptr = (const SourceDataType*)data.GetDataStart();
         }
         
-        data_ptr = (const SourceDataType*)data.GetDataStart();
-        
         lldb::DataBufferSP utf8_data_buffer_sp;
         UTF8* utf8_data_ptr = nullptr;
         UTF8* utf8_data_end_ptr = nullptr;
@@ -389,15 +392,17 @@ DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType
             utf8_data_end_ptr = (UTF8*)data_end_ptr;
         }
         
+        const bool escape_non_printables = dump_options.GetEscapeNonPrintables();
+        
         // since we tend to accept partial data (and even partially malformed data)
         // we might end up with no NULL terminator before the end_ptr
         // hence we need to take a slower route and ensure we stay within boundaries
         for (;utf8_data_ptr < utf8_data_end_ptr;)
         {
-            if (!*utf8_data_ptr)
+            if (zero_is_terminator && !*utf8_data_ptr)
                 break;
             
-            if (escapeNonPrintables)
+            if (escape_non_printables)
             {
                 uint8_t* next_data = nullptr;
                 auto printable = GetPrintable(StringElementType::UTF8, utf8_data_ptr, utf8_data_end_ptr, next_data);
@@ -421,8 +426,8 @@ DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType
             }
         }
     }
-    if (quote != 0)
-        stream.Printf("%c",quote);
+    if (dump_options.GetQuote() != 0)
+        stream.Printf("%c",dump_options.GetQuote());
     return true;
 }
 
@@ -438,6 +443,16 @@ lldb_private::formatters::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToS
     SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables());
 }
 
+lldb_private::formatters::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (const lldb_private::formatters::ReadStringAndDumpToStreamOptions& options) :
+    ReadBufferAndDumpToStreamOptions()
+{
+    SetStream(options.GetStream());
+    SetPrefixToken(options.GetPrefixToken());
+    SetQuote(options.GetQuote());
+    SetEscapeNonPrintables(options.GetEscapeNonPrintables());
+    SetBinaryZeroIsTerminator(options.GetBinaryZeroIsTerminator());
+}
+
 
 namespace lldb_private
 {
@@ -447,7 +462,7 @@ namespace formatters
 
 template <>
 bool
-ReadStringAndDumpToStream<StringElementType::ASCII> (ReadStringAndDumpToStreamOptions options)
+ReadStringAndDumpToStream<StringElementType::ASCII> (const ReadStringAndDumpToStreamOptions& options)
 {
     assert(options.GetStream() && "need a Stream to print the string to");
     Error my_error;
@@ -581,13 +596,17 @@ ReadUTFBufferAndDumpToStream (const ReadStringAndDumpToStreamOptions& options,
     }
 
     DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
+    
+    ReadBufferAndDumpToStreamOptions dump_options(options);
+    dump_options.SetData(data);
+    dump_options.SetSourceSize(sourceSize);
 
-    return DumpUTFBufferToStream(ConvertFunction, data, *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), sourceSize, options.GetEscapeNonPrintables());
+    return DumpUTFBufferToStream(ConvertFunction, dump_options);
 }
 
 template <>
 bool
-ReadStringAndDumpToStream<StringElementType::UTF8> (ReadStringAndDumpToStreamOptions options)
+ReadStringAndDumpToStream<StringElementType::UTF8> (const ReadStringAndDumpToStreamOptions& options)
 {
     return ReadUTFBufferAndDumpToStream<UTF8>(options,
                                               nullptr);
@@ -595,7 +614,7 @@ ReadStringAndDumpToStream<StringElementType::UTF8> (ReadStringAndDumpToStreamOpt
 
 template <>
 bool
-ReadStringAndDumpToStream<StringElementType::UTF16> (ReadStringAndDumpToStreamOptions options)
+ReadStringAndDumpToStream<StringElementType::UTF16> (const ReadStringAndDumpToStreamOptions& options)
 {
     return ReadUTFBufferAndDumpToStream<UTF16>(options,
                                                ConvertUTF16toUTF8);
@@ -603,7 +622,7 @@ ReadStringAndDumpToStream<StringElementType::UTF16> (ReadStringAndDumpToStreamOp
 
 template <>
 bool
-ReadStringAndDumpToStream<StringElementType::UTF32> (ReadStringAndDumpToStreamOptions options)
+ReadStringAndDumpToStream<StringElementType::UTF32> (const ReadStringAndDumpToStreamOptions& options)
 {
     return ReadUTFBufferAndDumpToStream<UTF32>(options,
                                                ConvertUTF32toUTF8);
@@ -611,16 +630,16 @@ ReadStringAndDumpToStream<StringElementType::UTF32> (ReadStringAndDumpToStreamOp
 
 template <>
 bool
-ReadBufferAndDumpToStream<StringElementType::UTF8> (ReadBufferAndDumpToStreamOptions options)
+ReadBufferAndDumpToStream<StringElementType::UTF8> (const ReadBufferAndDumpToStreamOptions& options)
 {
     assert(options.GetStream() && "need a Stream to print the string to");
 
-    return DumpUTFBufferToStream<UTF8>(nullptr, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables());
+    return DumpUTFBufferToStream<UTF8>(nullptr, options);
 }
 
 template <>
 bool
-ReadBufferAndDumpToStream<StringElementType::ASCII> (ReadBufferAndDumpToStreamOptions options)
+ReadBufferAndDumpToStream<StringElementType::ASCII> (const ReadBufferAndDumpToStreamOptions& options)
 {
     // treat ASCII the same as UTF8
     // FIXME: can we optimize ASCII some more?
@@ -629,20 +648,20 @@ ReadBufferAndDumpToStream<StringElementType::ASCII> (ReadBufferAndDumpToStreamOp
 
 template <>
 bool
-ReadBufferAndDumpToStream<StringElementType::UTF16> (ReadBufferAndDumpToStreamOptions options)
+ReadBufferAndDumpToStream<StringElementType::UTF16> (const ReadBufferAndDumpToStreamOptions& options)
 {
     assert(options.GetStream() && "need a Stream to print the string to");
 
-    return DumpUTFBufferToStream(ConvertUTF16toUTF8, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables());
+    return DumpUTFBufferToStream(ConvertUTF16toUTF8, options);
 }
 
 template <>
 bool
-ReadBufferAndDumpToStream<StringElementType::UTF32> (ReadBufferAndDumpToStreamOptions options)
+ReadBufferAndDumpToStream<StringElementType::UTF32> (const ReadBufferAndDumpToStreamOptions& options)
 {
     assert(options.GetStream() && "need a Stream to print the string to");
 
-    return DumpUTFBufferToStream(ConvertUTF32toUTF8, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables());
+    return DumpUTFBufferToStream(ConvertUTF32toUTF8, options);
 }
 
 } // namespace formatters
index fd3ecfe..ab3ec89 100644 (file)
@@ -64,7 +64,8 @@ class LibcxxStringDataFormatterTestCase(TestBase):
                     '(std::__1::wstring) S = L"!!!!"',
                     '(const wchar_t *) mazeltov = 0x','L"מזל טוב"',
                     '(std::__1::string) q = "hello world"',
-                    '(std::__1::string) Q = "quite a long std::strin with lots of info inside it"'])
+                    '(std::__1::string) Q = "quite a long std::strin with lots of info inside it"',
+                    '(std::__1::string) IHaveEmbeddedZeros = "a\\0b\\0c\\0d"'])
 
         self.runCmd("n")
 
@@ -86,7 +87,8 @@ class LibcxxStringDataFormatterTestCase(TestBase):
                     '(std::__1::wstring) S = L"!!!!!"',
                     '(const wchar_t *) mazeltov = 0x','L"מזל טוב"',
                     '(std::__1::string) q = "hello world"',
-                    '(std::__1::string) Q = "quite a long std::strin with lots of info inside it"'])
+                    '(std::__1::string) Q = "quite a long std::strin with lots of info inside it"',
+                    '(std::__1::string) IHaveEmbeddedZeros = "a\\0b\\0c\\0d"'])
 
 if __name__ == '__main__':
     import atexit
index 9ee3ae0..d31c921 100644 (file)
@@ -8,6 +8,7 @@ int main()
     std::string q("hello world");
     std::string Q("quite a long std::strin with lots of info inside it");
     std::string TheVeryLongOne("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890someText1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
+    std::string IHaveEmbeddedZeros("a\0b\0c\0d",7);
     S.assign(L"!!!!!"); // Set break point at this line.
     return 0;
 }