Skip to content

Commit ae44006

Browse files
clamp snprintf result before using it as fwrite length (#1185)
Backport of hrydgard/minitrace#49 (merged upstream as 679ac44) into the vendored copy. mtr_flush_with_state passed snprintf's would-be length to fwrite, so an event name longer than the 1024 byte line buffer made fwrite read past linebuf and copy stack bytes into the trace file. MinitraceLogger reaches this with any node name from the tree XML.
1 parent 0dd7e38 commit ae44006

2 files changed

Lines changed: 35 additions & 0 deletions

File tree

‎3rdparty/minitrace/minitrace.cpp‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,14 @@ void mtr_flush_with_state(int is_last) {
353353
len = snprintf(linebuf, ARRAY_SIZE(linebuf), "%s{\"cat\":\"%s\",\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 ",\"ph\":\"%c\",\"name\":\"%s\",\"args\":{%s}%s}",
354354
first_line ? "" : ",\n",
355355
cat, raw->pid, raw->tid, raw->ts - time_offset, raw->ph, raw->name, arg_buf, id_buf);
356+
// snprintf returns the length the line would have needed, not what it
357+
// wrote, and a negative value on error, so clamp before using it as a
358+
// write length.
359+
if (len < 0) {
360+
len = 0;
361+
} else if ((size_t)len >= sizeof(linebuf)) {
362+
len = (int)sizeof(linebuf) - 1;
363+
}
356364
fwrite(linebuf, 1, len, f);
357365
first_line = 0;
358366

‎tests/gtest_loggers.cpp‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,33 @@ TEST_F(LoggerTest, MinitraceLogger_TransitionTypes)
360360
ASSERT_TRUE(std::filesystem::exists(filepath));
361361
}
362362

363+
TEST_F(LoggerTest, MinitraceLogger_LongNodeName)
364+
{
365+
// The node name goes into a 1024 byte line buffer. A name long enough to
366+
// overflow it used to be written out with snprintf's would-be length, which
367+
// reads past the buffer and copies stack bytes into the trace file.
368+
const std::string long_name(1000, 'A');
369+
const std::string xml_text = R"(
370+
<root BTCPP_format="4">
371+
<BehaviorTree>
372+
<AlwaysSuccess name=")" +
373+
long_name + R"("/>
374+
</BehaviorTree>
375+
</root>)";
376+
377+
auto tree = factory.createTreeFromText(xml_text);
378+
std::string filepath = test_dir + "/trace_long_name.json";
379+
380+
{
381+
MinitraceLogger logger(tree, filepath.c_str());
382+
tree.tickWhileRunning();
383+
logger.flush();
384+
}
385+
386+
ASSERT_TRUE(std::filesystem::exists(filepath));
387+
ASSERT_LT(std::filesystem::file_size(filepath), 4096u);
388+
}
389+
363390
// ============ SqliteLogger tests ============
364391

365392
TEST_F(LoggerTest, SqliteLogger_Creation_db3)

0 commit comments

Comments
 (0)