aos: Fix `--force_timestamp_loading` for single-node logs
We're currently seeing a bunch of segfaults in log-reading code.
This is happening because the timestamp loading code
performs some checks against a list of source nodes. This list was
only populated for multi-node logs.
The fix here is to populate the list (with zeroes) even for
single-node logs. That lets the code proceed happily.
Before this patch I got the following crash for the new test:
$ bazel test --config=strict_ubsan @aos//aos/events/logging:logfile_utils_test -c opt
...
[ RUN ] SingleNodeTimestampMapperTest.QueueTimestampsForSingleNodes
external/llvm_k8/include/c++/v1/vector:1548:12: runtime error: reference binding to null pointer of type 'const value_type' (aka 'const unsigned long')
#0 0x7f404ba4197e (/data/phil_cache/bazel/_bazel_philipp/d441cd67cd5f527804d5d757edac2e45/execroot/shasta/bazel-out/k8-opt-ubsan/bin/external/aos/aos/events/logging/../../../../../_solib_k8/libexternal_Saos_Saos_Sevents_Slogging_Sliblogfile_Uutils.so+0x24197e) (BuildId: 64e54686062e7b4cd33e15bb59eb809a)
References: PRO-26639
Change-Id: I5a28f09af4f77da9b9aa2f36030394bd6d7e2e77
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/events/logging/logfile_utils.cc b/aos/events/logging/logfile_utils.cc
index 2e19f3c..0676577 100644
--- a/aos/events/logging/logfile_utils.cc
+++ b/aos/events/logging/logfile_utils.cc
@@ -2020,6 +2020,7 @@
queue_timestamps_ran_ = true;
return;
}
+ CHECK_LT(msg->channel_index, source_node.size());
if (source_node[msg->channel_index] != static_cast<size_t>(node())) {
timestamp_messages_.emplace_back(TimestampedMessage{
.channel_index = msg->channel_index,
@@ -2200,6 +2201,9 @@
source_node_.emplace_back(configuration::GetNodeIndex(
config, channel->source_node()->string_view()));
}
+ } else {
+ // The node index for single-node logs is always 0.
+ source_node_.resize(config->channels()->size(), 0);
}
}
diff --git a/aos/events/logging/logfile_utils_test.cc b/aos/events/logging/logfile_utils_test.cc
index 0c1cafd..4ceca20 100644
--- a/aos/events/logging/logfile_utils_test.cc
+++ b/aos/events/logging/logfile_utils_test.cc
@@ -326,11 +326,44 @@
return fbb2.Release();
}
+// Allows for some customization of a SortingElementTest.
+enum class SortingElementConfig {
+ // Create a single node configuration.
+ kSingleNode,
+ // Create a multi-node configuration.
+ kMultiNode,
+};
+
+template <SortingElementConfig sorting_element_config =
+ SortingElementConfig::kMultiNode>
class SortingElementTest : public ::testing::Test {
public:
SortingElementTest()
: config_(JsonToFlatbuffer<Configuration>(
- R"({
+ sorting_element_config == SortingElementConfig::kSingleNode ?
+ R"({
+ "channels": [
+ {
+ "name": "/a",
+ "type": "aos.logger.testing.TestMessage"
+ },
+ {
+ "name": "/b",
+ "type": "aos.logger.testing.TestMessage"
+ },
+ {
+ "name": "/c",
+ "type": "aos.logger.testing.TestMessage"
+ },
+ {
+ "name": "/d",
+ "type": "aos.logger.testing.TestMessage"
+ }
+ ]
+}
+)"
+ :
+ R"({
"channels": [
{
"name": "/a",
@@ -379,7 +412,31 @@
]
}
)")),
- config0_(MakeHeader(config_, R"({
+ config0_(MakeHeader(
+ config_, sorting_element_config == SortingElementConfig::kSingleNode
+ ?
+ R"({
+ /* 100ms */
+ "max_out_of_order_duration": 100000000,
+ "node": {
+ "name": "pi1"
+ },
+ "logger_node": {
+ "name": "pi1"
+ },
+ "monotonic_start_time": 1000000,
+ "realtime_start_time": 1000000000000,
+ "log_event_uuid": "30ef1283-81d7-4004-8c36-1c162dbcb2b2",
+ "source_node_boot_uuid": "1d782c63-b3c7-466e-bea9-a01308b43333",
+ "logger_node_boot_uuid": "1d782c63-b3c7-466e-bea9-a01308b43333",
+ "boot_uuids": [
+ "1d782c63-b3c7-466e-bea9-a01308b43333",
+ ],
+ "parts_uuid": "2a05d725-5d5c-4c0b-af42-88de2f3c3876",
+ "parts_index": 0
+})"
+ :
+ R"({
/* 100ms */
"max_out_of_order_duration": 100000000,
"node": {
@@ -593,10 +650,13 @@
std::vector<uint32_t> queue_index_;
};
-using MessageSorterTest = SortingElementTest;
+using MessageSorterTest = SortingElementTest<SortingElementConfig::kMultiNode>;
using MessageSorterDeathTest = MessageSorterTest;
-using PartsMergerTest = SortingElementTest;
-using TimestampMapperTest = SortingElementTest;
+using PartsMergerTest = SortingElementTest<SortingElementConfig::kMultiNode>;
+using TimestampMapperTest =
+ SortingElementTest<SortingElementConfig::kMultiNode>;
+using SingleNodeTimestampMapperTest =
+ SortingElementTest<SortingElementConfig::kSingleNode>;
// Tests that we can pull messages out of a log sorted in order.
TEST_F(MessageSorterTest, Pull) {
@@ -2065,7 +2125,44 @@
}
}
-class BootMergerTest : public SortingElementTest {
+// Validates that we can read timestamps on startup even for single-node logs.
+TEST_F(SingleNodeTimestampMapperTest, QueueTimestampsForSingleNodes) {
+ const aos::monotonic_clock::time_point e = monotonic_clock::epoch();
+ {
+ TestDetachedBufferWriter writer0(logfile0_);
+ writer0.QueueSpan(config0_.span());
+
+ writer0.WriteSizedFlatbuffer(
+ MakeLogMessage(e + chrono::milliseconds(1000), 0, 0x005));
+ writer0.WriteSizedFlatbuffer(
+ MakeLogMessage(e + chrono::milliseconds(2000), 0, 0x006));
+ writer0.WriteSizedFlatbuffer(
+ MakeLogMessage(e + chrono::milliseconds(2000), 0, 0x007));
+ writer0.WriteSizedFlatbuffer(
+ MakeLogMessage(e + chrono::milliseconds(3000), 0, 0x008));
+ }
+
+ const std::vector<LogFile> parts = SortParts({logfile0_});
+ LogFilesContainer log_files(parts);
+
+ ASSERT_EQ(parts[0].logger_node, "pi1");
+
+ size_t mapper0_count = 0;
+ TimestampMapper mapper0("pi1", log_files,
+ TimestampQueueStrategy::kQueueTimestampsAtStartup);
+ mapper0.set_timestamp_callback(
+ [&](TimestampedMessage *) { ++mapper0_count; });
+ mapper0.QueueTimestamps();
+
+ for (int i = 0; i < 4; ++i) {
+ ASSERT_TRUE(mapper0.Front() != nullptr);
+ mapper0.PopFront();
+ }
+ EXPECT_TRUE(mapper0.Front() == nullptr);
+ EXPECT_EQ(mapper0_count, 4u);
+}
+
+class BootMergerTest : public SortingElementTest<> {
public:
BootMergerTest()
: SortingElementTest(),
@@ -2204,7 +2301,7 @@
EXPECT_EQ(output[3].timestamp.time, e + chrono::milliseconds(200));
}
-class RebootTimestampMapperTest : public SortingElementTest {
+class RebootTimestampMapperTest : public SortingElementTest<> {
public:
RebootTimestampMapperTest()
: SortingElementTest(),
@@ -2730,7 +2827,7 @@
}
}
-class SortingDeathTest : public SortingElementTest {
+class SortingDeathTest : public SortingElementTest<> {
public:
SortingDeathTest()
: SortingElementTest(),