Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -767,6 +767,7 @@ 8C26C4261C3EA5F90031DF7C /* ThreadSanitizerRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C26C4241C3EA4340031DF7C /* ThreadSanitizerRuntime.cpp */; }; 8C2D6A53197A1EAF006989C9 /* MemoryHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2D6A52197A1EAF006989C9 /* MemoryHistory.cpp */; }; 8C2D6A5E197A250F006989C9 /* MemoryHistoryASan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */; }; + 8C3BD9A01EF5D1FF0016C343 /* JSONTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C3BD99F1EF5D1B50016C343 /* JSONTest.cpp */; }; 8C3BD9961EF45DA50016C343 /* MainThreadCheckerRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C3BD9951EF45D9B0016C343 /* MainThreadCheckerRuntime.cpp */; }; 8CCB017E19BA28A80009FD44 /* ThreadCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CCB017A19BA283D0009FD44 /* ThreadCollection.cpp */; }; 8CCB018219BA4E270009FD44 /* SBThreadCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CCB018119BA4E210009FD44 /* SBThreadCollection.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -2628,6 +2629,7 @@ 8C2D6A54197A1EBE006989C9 /* MemoryHistory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MemoryHistory.h; path = include/lldb/Target/MemoryHistory.h; sourceTree = ""; }; 8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryHistoryASan.cpp; sourceTree = ""; }; 8C2D6A5B197A1FDC006989C9 /* MemoryHistoryASan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryHistoryASan.h; sourceTree = ""; }; + 8C3BD99F1EF5D1B50016C343 /* JSONTest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSONTest.cpp; sourceTree = ""; }; 8C3BD9931EF45D9B0016C343 /* MainThreadCheckerRuntime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MainThreadCheckerRuntime.h; sourceTree = ""; }; 8C3BD9951EF45D9B0016C343 /* MainThreadCheckerRuntime.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MainThreadCheckerRuntime.cpp; sourceTree = ""; }; 8CCB017A19BA283D0009FD44 /* ThreadCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadCollection.cpp; path = source/Target/ThreadCollection.cpp; sourceTree = ""; }; @@ -3313,6 +3315,7 @@ 23CB15041D66CD9200EDDDE1 /* Inputs */, 2321F9441BDD346100BA9A93 /* StringExtractorTest.cpp */, 2321F9451BDD346100BA9A93 /* TaskPoolTest.cpp */, + 8C3BD99F1EF5D1B50016C343 /* JSONTest.cpp */, 2321F9461BDD346100BA9A93 /* UriParserTest.cpp */, ); path = Utility; @@ -7005,6 +7008,7 @@ 23CB15341D66DA9300EDDDE1 /* CPlusPlusLanguageTest.cpp in Sources */, AFAFD80A1E57E1B90017A14F /* ModuleCacheTest.cpp in Sources */, 23CB15351D66DA9300EDDDE1 /* UriParserTest.cpp in Sources */, + 8C3BD9A01EF5D1FF0016C343 /* JSONTest.cpp in Sources */, 23CB15361D66DA9300EDDDE1 /* FileSpecTest.cpp in Sources */, 23E2E5251D90373D006F38BB /* ArchSpecTest.cpp in Sources */, AF248A4D1DA71C77000B814D /* TestArm64InstEmulation.cpp in Sources */, Index: source/Utility/JSON.cpp =================================================================== --- source/Utility/JSON.cpp +++ source/Utility/JSON.cpp @@ -22,7 +22,7 @@ using namespace lldb_private; std::string JSONString::json_string_quote_metachars(const std::string &s) { - if (s.find('"') == std::string::npos) + if (s.find_first_of("\\\n\"") == std::string::npos) return s; std::string output; @@ -30,8 +30,9 @@ const char *s_chars = s.c_str(); for (size_t i = 0; i < s_size; i++) { unsigned char ch = *(s_chars + i); - if (ch == '"') { + if (ch == '"' || ch == '\\' || ch == '\n') { output.push_back('\\'); + if (ch == '\n') ch = 'n'; } output.push_back(ch); } Index: unittests/Utility/CMakeLists.txt =================================================================== --- unittests/Utility/CMakeLists.txt +++ unittests/Utility/CMakeLists.txt @@ -9,6 +9,7 @@ TaskPoolTest.cpp TildeExpressionResolverTest.cpp TimeoutTest.cpp + JSONTest.cpp UriParserTest.cpp VASprintfTest.cpp Index: unittests/Utility/JSONTest.cpp =================================================================== --- unittests/Utility/JSONTest.cpp +++ unittests/Utility/JSONTest.cpp @@ -0,0 +1,26 @@ +#include "gtest/gtest.h" + +#include "lldb/Core/StreamString.h" +#include "lldb/Utility/JSON.h" + +using namespace lldb_private; + +TEST(JSONTest, Dictionary) { + JSONObject o; + o.SetObject("key", std::make_shared("value")); + + StreamString stream; + o.Write(stream); + + ASSERT_EQ(stream.GetString(), R"({"key":"value"})"); +} + +TEST(JSONTest, Newlines) { + JSONObject o; + o.SetObject("key", std::make_shared("hello\nworld")); + + StreamString stream; + o.Write(stream); + + ASSERT_EQ(stream.GetString(), R"({"key":"hello\nworld"})"); +}