Skip to content

Commit a0d52cb

Browse files
committed
Add a check whether or not a str is utf8 prior to emplacing
Summary: Highlighing junk data on VSCode can send a query for evaluate which fails. In particular cases on Windows, this the error message can end up as a c-string of [-35,-35,-35,-35,...]. Attempting to emplace this as the error message causes an assert failure. Prior to emplacing the error message, confirm that it is valid UTF8 to eliminate errors such as mentione above. Reviewers: xiaobai, clayborg Reviewed By: clayborg Differential Revision: https://reviews.llvm.org/D53008 llvm-svn: 346988
1 parent cc14a32 commit a0d52cb

File tree

4 files changed

+65
-40
lines changed

4 files changed

+65
-40
lines changed

lldb/tools/lldb-vscode/JSONUtils.cpp

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@
2323

2424
namespace lldb_vscode {
2525

26+
void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key,
27+
llvm::StringRef str) {
28+
if (LLVM_LIKELY(llvm::json::isUTF8(str)))
29+
obj.try_emplace(key, str.str());
30+
else
31+
obj.try_emplace(key, llvm::json::fixUTF8(str));
32+
}
33+
2634
llvm::StringRef GetAsString(const llvm::json::Value &value) {
2735
if (auto s = value.getAsString())
2836
return *s;
@@ -124,11 +132,11 @@ std::vector<std::string> GetStrings(const llvm::json::Object *obj,
124132

125133
void SetValueForKey(lldb::SBValue &v, llvm::json::Object &object,
126134
llvm::StringRef key) {
127-
135+
128136
llvm::StringRef value = v.GetValue();
129137
llvm::StringRef summary = v.GetSummary();
130138
llvm::StringRef type_name = v.GetType().GetDisplayTypeName();
131-
139+
132140
std::string result;
133141
llvm::raw_string_ostream strm(result);
134142
if (!value.empty()) {
@@ -144,7 +152,7 @@ void SetValueForKey(lldb::SBValue &v, llvm::json::Object &object,
144152
strm << " @ " << llvm::format_hex(address, 0);
145153
}
146154
strm.flush();
147-
object.try_emplace(key, result);
155+
EmplaceSafeString(object, key, result);
148156
}
149157

150158
void FillResponse(const llvm::json::Object &request,
@@ -153,7 +161,7 @@ void FillResponse(const llvm::json::Object &request,
153161
// to true by default.
154162
response.try_emplace("type", "response");
155163
response.try_emplace("seq", (int64_t)0);
156-
response.try_emplace("command", GetString(request, "command"));
164+
EmplaceSafeString(response, "command", GetString(request, "command"));
157165
const int64_t seq = GetSigned(request, "seq", 0);
158166
response.try_emplace("request_seq", seq);
159167
response.try_emplace("success", true);
@@ -223,7 +231,7 @@ llvm::json::Value CreateScope(const llvm::StringRef name,
223231
int64_t variablesReference,
224232
int64_t namedVariables, bool expensive) {
225233
llvm::json::Object object;
226-
object.try_emplace("name", name.str());
234+
EmplaceSafeString(object, "name", name.str());
227235
object.try_emplace("variablesReference", variablesReference);
228236
object.try_emplace("expensive", expensive);
229237
object.try_emplace("namedVariables", namedVariables);
@@ -357,7 +365,7 @@ llvm::json::Object CreateEventObject(const llvm::StringRef event_name) {
357365
llvm::json::Object event;
358366
event.try_emplace("seq", 0);
359367
event.try_emplace("type", "event");
360-
event.try_emplace("event", event_name);
368+
EmplaceSafeString(event, "event", event_name);
361369
return event;
362370
}
363371

@@ -388,8 +396,8 @@ llvm::json::Object CreateEventObject(const llvm::StringRef event_name) {
388396
llvm::json::Value
389397
CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) {
390398
llvm::json::Object object;
391-
object.try_emplace("filter", bp.filter);
392-
object.try_emplace("label", bp.label);
399+
EmplaceSafeString(object, "filter", bp.filter);
400+
EmplaceSafeString(object, "label", bp.label);
393401
object.try_emplace("default", bp.default_value);
394402
return llvm::json::Value(std::move(object));
395403
}
@@ -467,11 +475,11 @@ llvm::json::Value CreateSource(lldb::SBLineEntry &line_entry) {
467475
if (file.IsValid()) {
468476
const char *name = file.GetFilename();
469477
if (name)
470-
object.try_emplace("name", name);
478+
EmplaceSafeString(object, "name", name);
471479
char path[PATH_MAX] = "";
472480
file.GetPath(path, sizeof(path));
473481
if (path[0]) {
474-
object.try_emplace("path", std::string(path));
482+
EmplaceSafeString(object, "path", std::string(path));
475483
}
476484
}
477485
return llvm::json::Value(std::move(object));
@@ -517,7 +525,7 @@ llvm::json::Value CreateSource(lldb::SBFrame &frame, int64_t &disasm_line) {
517525
}
518526
const auto num_insts = insts.GetSize();
519527
if (low_pc != LLDB_INVALID_ADDRESS && num_insts > 0) {
520-
object.try_emplace("name", frame.GetFunctionName());
528+
EmplaceSafeString(object, "name", frame.GetFunctionName());
521529
SourceReference source;
522530
llvm::raw_string_ostream src_strm(source.content);
523531
std::string line;
@@ -540,8 +548,8 @@ llvm::json::Value CreateSource(lldb::SBFrame &frame, int64_t &disasm_line) {
540548
line.clear();
541549
llvm::raw_string_ostream line_strm(line);
542550
line_strm << llvm::formatv("{0:X+}: <{1}> {2} {3,12} {4}", inst_addr,
543-
inst_offset, llvm::fmt_repeat(' ', spaces),
544-
m, o);
551+
inst_offset, llvm::fmt_repeat(' ', spaces), m,
552+
o);
545553

546554
// If there is a comment append it starting at column 60 or after one
547555
// space past the last char
@@ -626,7 +634,7 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame) {
626634
llvm::json::Object object;
627635
int64_t frame_id = MakeVSCodeFrameID(frame);
628636
object.try_emplace("id", frame_id);
629-
object.try_emplace("name", frame.GetFunctionName());
637+
EmplaceSafeString(object, "name", frame.GetFunctionName());
630638
int64_t disasm_line = 0;
631639
object.try_emplace("source", CreateSource(frame, disasm_line));
632640

@@ -670,9 +678,9 @@ llvm::json::Value CreateThread(lldb::SBThread &thread) {
670678
std::string thread_with_name(thread_str);
671679
thread_with_name += ' ';
672680
thread_with_name += name;
673-
object.try_emplace("name", thread_with_name);
681+
EmplaceSafeString(object, "name", thread_with_name);
674682
} else {
675-
object.try_emplace("name", std::string(thread_str));
683+
EmplaceSafeString(object, "name", std::string(thread_str));
676684
}
677685
return llvm::json::Value(std::move(object));
678686
}
@@ -749,7 +757,7 @@ llvm::json::Value CreateThreadStopped(lldb::SBThread &thread,
749757
ExceptionBreakpoint *exc_bp = g_vsc.GetExceptionBPFromStopReason(thread);
750758
if (exc_bp) {
751759
body.try_emplace("reason", "exception");
752-
body.try_emplace("description", exc_bp->label);
760+
EmplaceSafeString(body, "description", exc_bp->label);
753761
} else {
754762
body.try_emplace("reason", "breakpoint");
755763
}
@@ -782,7 +790,7 @@ llvm::json::Value CreateThreadStopped(lldb::SBThread &thread,
782790
if (ObjectContainsKey(body, "description")) {
783791
char description[1024];
784792
if (thread.GetStopDescription(description, sizeof(description))) {
785-
body.try_emplace("description", std::string(description));
793+
EmplaceSafeString(body, "description", std::string(description));
786794
}
787795
}
788796
if (tid == g_vsc.focus_tid) {
@@ -862,12 +870,12 @@ llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
862870
int64_t varID, bool format_hex) {
863871
llvm::json::Object object;
864872
auto name = v.GetName();
865-
object.try_emplace("name", name ? name : "<null>");
873+
EmplaceSafeString(object, "name", name ? name : "<null>");
866874
if (format_hex)
867875
v.SetFormat(lldb::eFormatHex);
868876
SetValueForKey(v, object, "value");
869877
auto type_cstr = v.GetType().GetDisplayTypeName();
870-
object.try_emplace("type", type_cstr ? type_cstr : NO_TYPENAME);
878+
EmplaceSafeString(object, "type", type_cstr ? type_cstr : NO_TYPENAME);
871879
if (varID != INT64_MAX)
872880
object.try_emplace("id", varID);
873881
if (v.MightHaveChildren())
@@ -878,7 +886,7 @@ llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
878886
v.GetExpressionPath(evaluateStream);
879887
const char *evaluateName = evaluateStream.GetData();
880888
if (evaluateName && evaluateName[0])
881-
object.try_emplace("evaluateName", std::string(evaluateName));
889+
EmplaceSafeString(object, "evaluateName", std::string(evaluateName));
882890
return llvm::json::Value(std::move(object));
883891
}
884892

lldb/tools/lldb-vscode/JSONUtils.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,24 @@
1616
#include "VSCodeForward.h"
1717

1818
namespace lldb_vscode {
19-
19+
20+
//------------------------------------------------------------------
21+
/// Emplace a StringRef in a json::Object after enusring that the
22+
/// string is valid UTF8. If not, first call llvm::json::fixUTF8
23+
/// before emplacing.
24+
///
25+
/// @param[in] obj
26+
/// A JSON object that we will attempt to emplace the value in
27+
///
28+
/// @param[in] key
29+
/// The key to use when emplacing the value
30+
///
31+
/// @param[in] str
32+
/// The string to emplace
33+
//------------------------------------------------------------------
34+
void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key,
35+
llvm::StringRef str);
36+
2037
//------------------------------------------------------------------
2138
/// Extract simple values as a string.
2239
///

lldb/tools/lldb-vscode/VSCode.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ void VSCode::SendOutput(OutputType o, const llvm::StringRef output) {
256256
break;
257257
}
258258
body.try_emplace("category", category);
259-
body.try_emplace("output", output.str());
259+
EmplaceSafeString(body, "output", output.str());
260260
event.try_emplace("body", std::move(body));
261261
SendJSON(llvm::json::Value(std::move(event)));
262262
}

lldb/tools/lldb-vscode/lldb-vscode.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ void SendProcessEvent(LaunchMethod launch_method) {
289289
exe_fspec.GetPath(exe_path, sizeof(exe_path));
290290
llvm::json::Object event(CreateEventObject("process"));
291291
llvm::json::Object body;
292-
body.try_emplace("name", std::string(exe_path));
292+
EmplaceSafeString(body, "name", std::string(exe_path));
293293
const auto pid = g_vsc.target.GetProcess().GetProcessID();
294294
body.try_emplace("systemProcessId", (int64_t)pid);
295295
body.try_emplace("isLocalProcess", true);
@@ -539,7 +539,7 @@ void request_attach(const llvm::json::Object &request) {
539539
g_vsc.target.AddModule(program.data(), target_triple, uuid_cstr, symfile);
540540
if (error.Fail()) {
541541
response.try_emplace("success", false);
542-
response.try_emplace("message", std::string(error.GetCString()));
542+
EmplaceSafeString(response, "message", std::string(error.GetCString()));
543543
g_vsc.SendJSON(llvm::json::Value(std::move(response)));
544544
return;
545545
}
@@ -591,7 +591,7 @@ void request_attach(const llvm::json::Object &request) {
591591

592592
if (error.Fail()) {
593593
response.try_emplace("success", false);
594-
response.try_emplace("message", std::string(error.GetCString()));
594+
EmplaceSafeString(response, "message", std::string(error.GetCString()));
595595
}
596596
g_vsc.SendJSON(llvm::json::Value(std::move(response)));
597597
if (error.Success()) {
@@ -813,8 +813,8 @@ void request_exceptionInfo(const llvm::json::Object &request) {
813813
else if (stopReason == lldb::eStopReasonBreakpoint) {
814814
ExceptionBreakpoint *exc_bp = g_vsc.GetExceptionBPFromStopReason(thread);
815815
if (exc_bp) {
816-
body.try_emplace("exceptionId", exc_bp->filter);
817-
body.try_emplace("description", exc_bp->label);
816+
EmplaceSafeString(body, "exceptionId", exc_bp->filter);
817+
EmplaceSafeString(body, "description", exc_bp->label);
818818
} else {
819819
body.try_emplace("exceptionId", "exception");
820820
}
@@ -824,7 +824,7 @@ void request_exceptionInfo(const llvm::json::Object &request) {
824824
if (!ObjectContainsKey(body, "description")) {
825825
char description[1024];
826826
if (thread.GetStopDescription(description, sizeof(description))) {
827-
body.try_emplace("description", std::string(description));
827+
EmplaceSafeString(body, "description", std::string(description));
828828
}
829829
}
830830
body.try_emplace("breakMode", "always");
@@ -951,9 +951,9 @@ void request_evaluate(const llvm::json::Object &request) {
951951
const auto expression = GetString(arguments, "expression");
952952

953953
if (!expression.empty() && expression[0] == '`') {
954-
body.try_emplace("result",
955-
RunLLDBCommands(llvm::StringRef(),
956-
{expression.substr(1)}));
954+
auto result = RunLLDBCommands(llvm::StringRef(),
955+
{expression.substr(1)});
956+
EmplaceSafeString(body, "result", result);
957957
body.try_emplace("variablesReference", (int64_t)0);
958958
} else {
959959
// Always try to get the answer from the local variables if possible. If
@@ -968,13 +968,13 @@ void request_evaluate(const llvm::json::Object &request) {
968968
response.try_emplace("success", false);
969969
const char *error_cstr = value.GetError().GetCString();
970970
if (error_cstr && error_cstr[0])
971-
response.try_emplace("message", std::string(error_cstr));
971+
EmplaceSafeString(response, "message", std::string(error_cstr));
972972
else
973-
response.try_emplace("message", "evaluate failed");
973+
EmplaceSafeString(response, "message", "evaluate failed");
974974
} else {
975975
SetValueForKey(value, body, "result");
976976
auto value_typename = value.GetType().GetDisplayTypeName();
977-
body.try_emplace("type", value_typename ? value_typename : NO_TYPENAME);
977+
EmplaceSafeString(body, "type", value_typename ? value_typename : NO_TYPENAME);
978978
if (value.MightHaveChildren()) {
979979
auto variablesReference = VARIDX_TO_VARREF(g_vsc.variables.GetSize());
980980
g_vsc.variables.Append(value);
@@ -1241,7 +1241,7 @@ void request_launch(const llvm::json::Object &request) {
12411241
g_vsc.target.AddModule(program.data(), target_triple, uuid_cstr, symfile);
12421242
if (error.Fail()) {
12431243
response.try_emplace("success", false);
1244-
response.try_emplace("message", std::string(error.GetCString()));
1244+
EmplaceSafeString(response, "message", std::string(error.GetCString()));
12451245
g_vsc.SendJSON(llvm::json::Value(std::move(response)));
12461246
}
12471247
}
@@ -1279,7 +1279,7 @@ void request_launch(const llvm::json::Object &request) {
12791279
g_vsc.target.Launch(g_vsc.launch_info, error);
12801280
if (error.Fail()) {
12811281
response.try_emplace("success", false);
1282-
response.try_emplace("message", std::string(error.GetCString()));
1282+
EmplaceSafeString(response, "message", std::string(error.GetCString()));
12831283
}
12841284
g_vsc.SendJSON(llvm::json::Value(std::move(response)));
12851285

@@ -1945,7 +1945,7 @@ void request_source(const llvm::json::Object &request) {
19451945
auto sourceReference = GetSigned(source, "sourceReference", -1);
19461946
auto pos = g_vsc.source_map.find((lldb::addr_t)sourceReference);
19471947
if (pos != g_vsc.source_map.end()) {
1948-
body.try_emplace("content", pos->second.content);
1948+
EmplaceSafeString(body, "content", pos->second.content);
19491949
} else {
19501950
response.try_emplace("success", false);
19511951
}
@@ -2406,10 +2406,10 @@ void request_setVariable(const llvm::json::Object &request) {
24062406
bool success = variable.SetValueFromCString(value.data(), error);
24072407
if (success) {
24082408
SetValueForKey(variable, body, "value");
2409-
body.try_emplace("type", variable.GetType().GetDisplayTypeName());
2409+
EmplaceSafeString(body, "type", variable.GetType().GetDisplayTypeName());
24102410
body.try_emplace("variablesReference", newVariablesReference);
24112411
} else {
2412-
body.try_emplace("message", std::string(error.GetCString()));
2412+
EmplaceSafeString(body, "message", std::string(error.GetCString()));
24132413
}
24142414
response.try_emplace("success", success);
24152415
}

0 commit comments

Comments
 (0)