Actually enforce the size in ChannelPreallocatedAllocator
We were ignoring the size when being asked to allocate. Turns out
Flatbuffers rounds alignment up, so a 300 byte request becomes 304
bytes, corrupting the redzone. Add a bunch of CHECKs here to catch it,
teach EventLoop to catch it, and catch it in the compiler.
Change-Id: I10488a2f96eeb7a955c6da436e6f9de1fcebbd14
diff --git a/aos/config_flattener.cc b/aos/config_flattener.cc
index d39cd50..83959a1 100644
--- a/aos/config_flattener.cc
+++ b/aos/config_flattener.cc
@@ -25,6 +25,15 @@
FlatbufferDetachedBuffer<Configuration> config =
configuration::ReadConfig(config_path, {bazel_outs_directory});
+ for (const Channel *channel : *config.message().channels()) {
+ if (channel->max_size() % alignof(flatbuffers::largest_scalar_t) != 0) {
+ LOG(FATAL) << "max_size() (" << channel->max_size()
+ << ") is not a multiple of alignment ("
+ << alignof(flatbuffers::largest_scalar_t) << ") for channel "
+ << configuration::CleanedChannelToString(channel) << ".";
+ }
+ }
+
std::vector<aos::FlatbufferString<reflection::Schema>> schemas;
for (int i = 5; i < argc; ++i) {
diff --git a/aos/events/channel_preallocated_allocator.h b/aos/events/channel_preallocated_allocator.h
index 5ca370b..c4f0eca 100644
--- a/aos/events/channel_preallocated_allocator.h
+++ b/aos/events/channel_preallocated_allocator.h
@@ -34,17 +34,30 @@
~ChannelPreallocatedAllocator() override { CHECK(!is_allocated_); }
// TODO(austin): Read the contract for these.
- uint8_t *allocate(size_t /*size*/) override {
+ uint8_t *allocate(size_t size) override {
if (is_allocated_) {
- LOG(FATAL) << "Can't allocate more memory with a fixed size allocator. "
- "Increase the memory reserved.";
+ LOG(FATAL) << "Can't allocate more memory with a fixed size allocator on "
+ "channel "
+ << configuration::CleanedChannelToString(channel_);
}
+ CHECK_LE(size, size_)
+ << ": Tried to allocate more space than available on channel "
+ << configuration::CleanedChannelToString(channel_);
+
is_allocated_ = true;
return data_;
}
- void deallocate(uint8_t *, size_t) override { is_allocated_ = false; }
+ void deallocate(uint8_t *data, size_t size) override {
+ CHECK_EQ(data, data_)
+ << ": Deallocating data not allocated here on channel "
+ << configuration::CleanedChannelToString(channel_);
+ CHECK_LE(size, size_)
+ << ": Tried to deallocate more space than available on channel "
+ << configuration::CleanedChannelToString(channel_);
+ is_allocated_ = false;
+ }
uint8_t *reallocate_downward(uint8_t * /*old_p*/, size_t /*old_size*/,
size_t new_size, size_t /*in_use_back*/,
diff --git a/aos/events/event_loop.cc b/aos/events/event_loop.cc
index 5c7e49d..639e337 100644
--- a/aos/events/event_loop.cc
+++ b/aos/events/event_loop.cc
@@ -10,6 +10,16 @@
"Period in milliseconds to publish timing reports at.");
namespace aos {
+namespace {
+void CheckAlignment(const Channel *channel) {
+ if (channel->max_size() % alignof(flatbuffers::largest_scalar_t) != 0) {
+ LOG(FATAL) << "max_size() (" << channel->max_size()
+ << ") is not a multiple of alignment ("
+ << alignof(flatbuffers::largest_scalar_t) << ") for channel "
+ << configuration::CleanedChannelToString(channel) << ".";
+ }
+}
+} // namespace
RawSender::RawSender(EventLoop *event_loop, const Channel *channel)
: event_loop_(event_loop),
@@ -120,6 +130,8 @@
}
void EventLoop::NewFetcher(RawFetcher *fetcher) {
+ CheckAlignment(fetcher->channel());
+
fetchers_.emplace_back(fetcher);
UpdateTimingReport();
}
@@ -144,6 +156,8 @@
CHECK(!is_running()) << ": Cannot add new objects while running.";
ChannelIndex(channel);
+ CheckAlignment(channel);
+
CHECK(taken_senders_.find(channel) == taken_senders_.end())
<< ": " << configuration::CleanedChannelToString(channel)
<< " is already being used.";
@@ -163,6 +177,8 @@
CHECK(!is_running()) << ": Cannot add new objects while running.";
ChannelIndex(channel);
+ CheckAlignment(channel);
+
CHECK(taken_watchers_.find(channel) == taken_watchers_.end())
<< ": Channel " << configuration::CleanedChannelToString(channel)
<< " is already being used.";
diff --git a/aos/events/event_loop_param_test.cc b/aos/events/event_loop_param_test.cc
index 993011f..979de74 100644
--- a/aos/events/event_loop_param_test.cc
+++ b/aos/events/event_loop_param_test.cc
@@ -1158,6 +1158,35 @@
"Channel pointer not found in configuration\\(\\)->channels\\(\\)");
}
+// Verifies that the event loop implementations detect when Channel has an
+// invalid alignment.
+TEST_P(AbstractEventLoopDeathTest, InvalidChannelAlignment) {
+ const char *const kError = "multiple of alignment";
+ InvalidChannelAlignment();
+
+ auto loop = MakePrimary();
+
+ const Channel *channel = configuration::GetChannel(
+ loop->configuration(), "/test", "aos.TestMessage", "", nullptr);
+
+ EXPECT_DEATH({ loop->MakeRawSender(channel); }, kError);
+ EXPECT_DEATH({ loop->MakeSender<TestMessage>("/test"); }, kError);
+
+ EXPECT_DEATH({ loop->MakeRawFetcher(channel); }, kError);
+ EXPECT_DEATH({ loop->MakeFetcher<TestMessage>("/test"); }, kError);
+
+ EXPECT_DEATH(
+ { loop->MakeRawWatcher(channel, [](const Context &, const void *) {}); },
+ kError);
+ EXPECT_DEATH({ loop->MakeRawNoArgWatcher(channel, [](const Context &) {}); },
+ kError);
+
+ EXPECT_DEATH({ loop->MakeNoArgWatcher<TestMessage>("/test", []() {}); },
+ kError);
+ EXPECT_DEATH({ loop->MakeWatcher("/test", [](const TestMessage &) {}); },
+ kError);
+}
+
// Verify that the send time on a message is roughly right when using a watcher.
TEST_P(AbstractEventLoopTest, MessageSendTime) {
auto loop1 = MakePrimary();
diff --git a/aos/events/event_loop_param_test.h b/aos/events/event_loop_param_test.h
index 57d0525..85e802b 100644
--- a/aos/events/event_loop_param_test.h
+++ b/aos/events/event_loop_param_test.h
@@ -59,6 +59,35 @@
// Advances time by sleeping. Can't be called from inside a loop.
virtual void SleepFor(::std::chrono::nanoseconds duration) = 0;
+ // Sets the config to a config with a max size with an invalid alignment.
+ void InvalidChannelAlignment() {
+ flatbuffer_ = JsonToFlatbuffer<Configuration>(R"config({
+ "channels": [
+ {
+ "name": "/aos",
+ "type": "aos.logging.LogMessageFbs"
+ },
+ {
+ "name": "/aos",
+ "type": "aos.timing.Report"
+ },
+ {
+ "name": "/test",
+ "type": "aos.TestMessage",
+ "max_size": 13
+ },
+ {
+ "name": "/test1",
+ "type": "aos.TestMessage"
+ },
+ {
+ "name": "/test2",
+ "type": "aos.TestMessage"
+ }
+ ]
+})config");
+ }
+
void PinReads() {
static const std::string kJson = R"config({
"channels": [
@@ -245,6 +274,8 @@
return factory_->MakePrimary(name);
}
+ void InvalidChannelAlignment() { factory_->InvalidChannelAlignment(); }
+
void EnableNodes(std::string_view my_node) { factory_->EnableNodes(my_node); }
void Run() { return factory_->Run(); }
diff --git a/aos/network/www/test_config_file.json b/aos/network/www/test_config_file.json
index 09b22dd..39b8ef1 100644
--- a/aos/network/www/test_config_file.json
+++ b/aos/network/www/test_config_file.json
@@ -10,7 +10,7 @@
"name": "/test",
"type": "aos.Configuration",
"source_node": "roborio",
- "max_size": 1678,
+ "max_size": 2056,
"frequency": 200
}
],
diff --git a/y2020/y2020_laptop.json b/y2020/y2020_laptop.json
index 0797110..37961f8 100644
--- a/y2020/y2020_laptop.json
+++ b/y2020/y2020_laptop.json
@@ -135,7 +135,7 @@
"source_node": "laptop",
"frequency": 10,
"num_senders": 2,
- "max_size": 300,
+ "max_size": 400,
"destination_nodes": [
{
"name": "pi1",
@@ -181,7 +181,7 @@
"logger": "NOT_LOGGED",
"frequency": 20,
"num_senders": 2,
- "max_size": 300
+ "max_size": 200
},
{
"name": "/laptop/aos/remote_timestamps/pi1",
@@ -190,7 +190,7 @@
"logger": "NOT_LOGGED",
"frequency": 20,
"num_senders": 2,
- "max_size": 300
+ "max_size": 200
},
{
"name": "/laptop/aos/remote_timestamps/pi2",
@@ -199,7 +199,7 @@
"logger": "NOT_LOGGED",
"frequency": 20,
"num_senders": 2,
- "max_size": 300
+ "max_size": 200
},
{
"name": "/laptop/aos/remote_timestamps/pi3",
@@ -208,7 +208,7 @@
"logger": "NOT_LOGGED",
"frequency": 20,
"num_senders": 2,
- "max_size": 300
+ "max_size": 200
},
{
"name": "/laptop/aos/remote_timestamps/pi4",
@@ -217,7 +217,7 @@
"logger": "NOT_LOGGED",
"frequency": 20,
"num_senders": 2,
- "max_size": 300
+ "max_size": 200
},
{
"name": "/pi1/camera",
diff --git a/y2020/y2020_roborio.json b/y2020/y2020_roborio.json
index b63982d..0ab9664 100644
--- a/y2020/y2020_roborio.json
+++ b/y2020/y2020_roborio.json
@@ -74,7 +74,7 @@
"source_node": "roborio",
"frequency": 10,
"num_senders": 2,
- "max_size": 300,
+ "max_size": 400,
"destination_nodes": [
{
"name": "pi1",