Index: tools/lldb-vscode/JSONUtils.h =================================================================== --- tools/lldb-vscode/JSONUtils.h +++ tools/lldb-vscode/JSONUtils.h @@ -16,7 +16,24 @@ #include "VSCodeForward.h" namespace lldb_vscode { - + +//------------------------------------------------------------------ +/// Emplace a StringRef in a json::Object after enusring that the +/// string is valid UTF8. If not, first call llvm::json::fixUTF8 +/// before emplacing. +/// +/// @param[in] obj +/// A JSON object that we will attempt to emplace the value in +/// +/// @param[in] key +/// The key to use when emplacing the value +/// +/// @param[in] str +/// The string to emplace +//------------------------------------------------------------------ +void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key, + llvm::StringRef str); + //------------------------------------------------------------------ /// Extract simple values as a string. /// Index: tools/lldb-vscode/JSONUtils.cpp =================================================================== --- tools/lldb-vscode/JSONUtils.cpp +++ tools/lldb-vscode/JSONUtils.cpp @@ -23,6 +23,14 @@ namespace lldb_vscode { +void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key, + llvm::StringRef str) { + if (LLVM_LIKELY(llvm::json::isUTF8(str))) + obj.try_emplace(key, str.str()); + else + obj.try_emplace(key, llvm::json::fixUTF8(str)); +} + llvm::StringRef GetAsString(const llvm::json::Value &value) { if (auto s = value.getAsString()) return *s; @@ -124,11 +132,11 @@ void SetValueForKey(lldb::SBValue &v, llvm::json::Object &object, llvm::StringRef key) { - + llvm::StringRef value = v.GetValue(); llvm::StringRef summary = v.GetSummary(); llvm::StringRef type_name = v.GetType().GetDisplayTypeName(); - + std::string result; llvm::raw_string_ostream strm(result); if (!value.empty()) { @@ -144,7 +152,7 @@ strm << " @ " << llvm::format_hex(address, 0); } strm.flush(); - object.try_emplace(key, result); + EmplaceSafeString(object, key, result); } void FillResponse(const llvm::json::Object &request, @@ -153,7 +161,7 @@ // to true by default. response.try_emplace("type", "response"); response.try_emplace("seq", (int64_t)0); - response.try_emplace("command", GetString(request, "command")); + EmplaceSafeString(response, "command", GetString(request, "command")); const int64_t seq = GetSigned(request, "seq", 0); response.try_emplace("request_seq", seq); response.try_emplace("success", true); @@ -223,7 +231,7 @@ int64_t variablesReference, int64_t namedVariables, bool expensive) { llvm::json::Object object; - object.try_emplace("name", name.str()); + EmplaceSafeString(object, "name", name.str()); object.try_emplace("variablesReference", variablesReference); object.try_emplace("expensive", expensive); object.try_emplace("namedVariables", namedVariables); @@ -357,7 +365,7 @@ llvm::json::Object event; event.try_emplace("seq", 0); event.try_emplace("type", "event"); - event.try_emplace("event", event_name); + EmplaceSafeString(event, "event", event_name); return event; } @@ -388,8 +396,8 @@ llvm::json::Value CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) { llvm::json::Object object; - object.try_emplace("filter", bp.filter); - object.try_emplace("label", bp.label); + EmplaceSafeString(object, "filter", bp.filter); + EmplaceSafeString(object, "label", bp.label); object.try_emplace("default", bp.default_value); return llvm::json::Value(std::move(object)); } @@ -467,11 +475,11 @@ if (file.IsValid()) { const char *name = file.GetFilename(); if (name) - object.try_emplace("name", name); + EmplaceSafeString(object, "name", name); char path[PATH_MAX] = ""; file.GetPath(path, sizeof(path)); if (path[0]) { - object.try_emplace("path", std::string(path)); + EmplaceSafeString(object, "path", std::string(path)); } } return llvm::json::Value(std::move(object)); @@ -517,7 +525,7 @@ } const auto num_insts = insts.GetSize(); if (low_pc != LLDB_INVALID_ADDRESS && num_insts > 0) { - object.try_emplace("name", frame.GetFunctionName()); + EmplaceSafeString(object, "name", frame.GetFunctionName()); SourceReference source; llvm::raw_string_ostream src_strm(source.content); std::string line; @@ -540,8 +548,8 @@ line.clear(); llvm::raw_string_ostream line_strm(line); line_strm << llvm::formatv("{0:X+}: <{1}> {2} {3,12} {4}", inst_addr, - inst_offset, llvm::fmt_repeat(' ', spaces), - m, o); + inst_offset, llvm::fmt_repeat(' ', spaces), m, + o); // If there is a comment append it starting at column 60 or after one // space past the last char @@ -626,7 +634,7 @@ llvm::json::Object object; int64_t frame_id = MakeVSCodeFrameID(frame); object.try_emplace("id", frame_id); - object.try_emplace("name", frame.GetFunctionName()); + EmplaceSafeString(object, "name", frame.GetFunctionName()); int64_t disasm_line = 0; object.try_emplace("source", CreateSource(frame, disasm_line)); @@ -670,9 +678,9 @@ std::string thread_with_name(thread_str); thread_with_name += ' '; thread_with_name += name; - object.try_emplace("name", thread_with_name); + EmplaceSafeString(object, "name", thread_with_name); } else { - object.try_emplace("name", std::string(thread_str)); + EmplaceSafeString(object, "name", std::string(thread_str)); } return llvm::json::Value(std::move(object)); } @@ -749,7 +757,7 @@ ExceptionBreakpoint *exc_bp = g_vsc.GetExceptionBPFromStopReason(thread); if (exc_bp) { body.try_emplace("reason", "exception"); - body.try_emplace("description", exc_bp->label); + EmplaceSafeString(body, "description", exc_bp->label); } else { body.try_emplace("reason", "breakpoint"); } @@ -782,7 +790,7 @@ if (ObjectContainsKey(body, "description")) { char description[1024]; if (thread.GetStopDescription(description, sizeof(description))) { - body.try_emplace("description", std::string(description)); + EmplaceSafeString(body, "description", std::string(description)); } } if (tid == g_vsc.focus_tid) { @@ -862,12 +870,12 @@ int64_t varID, bool format_hex) { llvm::json::Object object; auto name = v.GetName(); - object.try_emplace("name", name ? name : ""); + EmplaceSafeString(object, "name", name ? name : ""); if (format_hex) v.SetFormat(lldb::eFormatHex); SetValueForKey(v, object, "value"); auto type_cstr = v.GetType().GetDisplayTypeName(); - object.try_emplace("type", type_cstr ? type_cstr : NO_TYPENAME); + EmplaceSafeString(object, "type", type_cstr ? type_cstr : NO_TYPENAME); if (varID != INT64_MAX) object.try_emplace("id", varID); if (v.MightHaveChildren()) @@ -878,7 +886,7 @@ v.GetExpressionPath(evaluateStream); const char *evaluateName = evaluateStream.GetData(); if (evaluateName && evaluateName[0]) - object.try_emplace("evaluateName", std::string(evaluateName)); + EmplaceSafeString(object, "evaluateName", std::string(evaluateName)); return llvm::json::Value(std::move(object)); } Index: tools/lldb-vscode/VSCode.cpp =================================================================== --- tools/lldb-vscode/VSCode.cpp +++ tools/lldb-vscode/VSCode.cpp @@ -256,7 +256,7 @@ break; } body.try_emplace("category", category); - body.try_emplace("output", output.str()); + EmplaceSafeString(body, "output", output.str()); event.try_emplace("body", std::move(body)); SendJSON(llvm::json::Value(std::move(event))); } Index: tools/lldb-vscode/lldb-vscode.cpp =================================================================== --- tools/lldb-vscode/lldb-vscode.cpp +++ tools/lldb-vscode/lldb-vscode.cpp @@ -289,7 +289,7 @@ exe_fspec.GetPath(exe_path, sizeof(exe_path)); llvm::json::Object event(CreateEventObject("process")); llvm::json::Object body; - body.try_emplace("name", std::string(exe_path)); + EmplaceSafeString(body, "name", std::string(exe_path)); const auto pid = g_vsc.target.GetProcess().GetProcessID(); body.try_emplace("systemProcessId", (int64_t)pid); body.try_emplace("isLocalProcess", true); @@ -539,7 +539,7 @@ g_vsc.target.AddModule(program.data(), target_triple, uuid_cstr, symfile); if (error.Fail()) { response.try_emplace("success", false); - response.try_emplace("message", std::string(error.GetCString())); + EmplaceSafeString(response, "message", std::string(error.GetCString())); g_vsc.SendJSON(llvm::json::Value(std::move(response))); return; } @@ -591,7 +591,7 @@ if (error.Fail()) { response.try_emplace("success", false); - response.try_emplace("message", std::string(error.GetCString())); + EmplaceSafeString(response, "message", std::string(error.GetCString())); } g_vsc.SendJSON(llvm::json::Value(std::move(response))); if (error.Success()) { @@ -813,8 +813,8 @@ else if (stopReason == lldb::eStopReasonBreakpoint) { ExceptionBreakpoint *exc_bp = g_vsc.GetExceptionBPFromStopReason(thread); if (exc_bp) { - body.try_emplace("exceptionId", exc_bp->filter); - body.try_emplace("description", exc_bp->label); + EmplaceSafeString(body, "exceptionId", exc_bp->filter); + EmplaceSafeString(body, "description", exc_bp->label); } else { body.try_emplace("exceptionId", "exception"); } @@ -824,7 +824,7 @@ if (!ObjectContainsKey(body, "description")) { char description[1024]; if (thread.GetStopDescription(description, sizeof(description))) { - body.try_emplace("description", std::string(description)); + EmplaceSafeString(body, "description", std::string(description)); } } body.try_emplace("breakMode", "always"); @@ -951,9 +951,9 @@ const auto expression = GetString(arguments, "expression"); if (!expression.empty() && expression[0] == '`') { - body.try_emplace("result", - RunLLDBCommands(llvm::StringRef(), - {expression.substr(1)})); + auto result = RunLLDBCommands(llvm::StringRef(), + {expression.substr(1)}); + EmplaceSafeString(body, "result", result); body.try_emplace("variablesReference", (int64_t)0); } else { // Always try to get the answer from the local variables if possible. If @@ -968,13 +968,13 @@ response.try_emplace("success", false); const char *error_cstr = value.GetError().GetCString(); if (error_cstr && error_cstr[0]) - response.try_emplace("message", std::string(error_cstr)); + EmplaceSafeString(response, "message", std::string(error_cstr)); else - response.try_emplace("message", "evaluate failed"); + EmplaceSafeString(response, "message", "evaluate failed"); } else { SetValueForKey(value, body, "result"); auto value_typename = value.GetType().GetDisplayTypeName(); - body.try_emplace("type", value_typename ? value_typename : NO_TYPENAME); + EmplaceSafeString(body, "type", value_typename ? value_typename : NO_TYPENAME); if (value.MightHaveChildren()) { auto variablesReference = VARIDX_TO_VARREF(g_vsc.variables.GetSize()); g_vsc.variables.Append(value); @@ -1241,7 +1241,7 @@ g_vsc.target.AddModule(program.data(), target_triple, uuid_cstr, symfile); if (error.Fail()) { response.try_emplace("success", false); - response.try_emplace("message", std::string(error.GetCString())); + EmplaceSafeString(response, "message", std::string(error.GetCString())); g_vsc.SendJSON(llvm::json::Value(std::move(response))); } } @@ -1279,7 +1279,7 @@ g_vsc.target.Launch(g_vsc.launch_info, error); if (error.Fail()) { response.try_emplace("success", false); - response.try_emplace("message", std::string(error.GetCString())); + EmplaceSafeString(response, "message", std::string(error.GetCString())); } g_vsc.SendJSON(llvm::json::Value(std::move(response))); @@ -1945,7 +1945,7 @@ auto sourceReference = GetSigned(source, "sourceReference", -1); auto pos = g_vsc.source_map.find((lldb::addr_t)sourceReference); if (pos != g_vsc.source_map.end()) { - body.try_emplace("content", pos->second.content); + EmplaceSafeString(body, "content", pos->second.content); } else { response.try_emplace("success", false); } @@ -2406,10 +2406,10 @@ bool success = variable.SetValueFromCString(value.data(), error); if (success) { SetValueForKey(variable, body, "value"); - body.try_emplace("type", variable.GetType().GetDisplayTypeName()); + EmplaceSafeString(body, "type", variable.GetType().GetDisplayTypeName()); body.try_emplace("variablesReference", newVariablesReference); } else { - body.try_emplace("message", std::string(error.GetCString())); + EmplaceSafeString(body, "message", std::string(error.GetCString())); } response.try_emplace("success", success); }