Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions netkat/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ cc_library(
deps = [
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/log",
"@com_google_absl//absl/log:check",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/strings:string_view",
Expand Down
13 changes: 13 additions & 0 deletions netkat/packet_field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@

#include "netkat/packet_field.h"

#include <cstdint>
#include <limits>
#include <string>

#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
Expand All @@ -25,6 +28,16 @@ namespace netkat {

PacketFieldHandle PacketFieldManager::GetOrCreatePacketFieldHandle(
absl::string_view field_name) {
// `PacketFieldHandle` packs its index into a 16-bit field (see
// packet_field.h), so silently truncating an index that no longer fits
// would let two distinct field names collide on the same handle. Fail
// loudly instead, since that's a violation of a documented, load-bearing
// assumption rather than a recoverable runtime condition.
CHECK_LE(field_names_.size(), // Crash OK
std::numeric_limits<uint16_t>::max())
<< "PacketFieldManager: exceeded the maximum of "
<< std::numeric_limits<uint16_t>::max() + 1 << " distinct packet fields.";

auto [it, inserted] = packet_field_by_name_.try_emplace(
field_name, PacketFieldHandle(field_names_.size()));
if (inserted) field_names_.push_back(std::string(field_name));
Expand Down
21 changes: 21 additions & 0 deletions netkat/packet_field_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,26 @@ TEST(PacketFieldManagerTest, GetFieldNameReturnsNameOfPacketFieldHandle) {
EXPECT_EQ(Manager().GetFieldName(foo), "foo");
EXPECT_EQ(Manager().GetFieldName(bar), "bar");
}

// `PacketFieldHandle` packs its index into 16 bits (see packet_field.h), so
// the manager must reject attempts to intern more than 2^16 distinct field
// names instead of silently truncating the index and aliasing two different
// field names onto the same handle.
//
// Uses a manager local to this test (rather than the shared `Manager()`
// above) so as to not pollute global test state with tens of thousands of
// interned fields.
TEST(PacketFieldManagerTest,
GetOrCreatePacketFieldHandleCrashesOnTooManyDistinctFields) {
PacketFieldManager manager;
constexpr int kMaxDistinctFields = 1 << 16;
for (int i = 0; i < kMaxDistinctFields; ++i) {
(void)manager.GetOrCreatePacketFieldHandle(absl::StrCat("field_", i));
}
EXPECT_DEATH(
(void)manager.GetOrCreatePacketFieldHandle(
absl::StrCat("field_", kMaxDistinctFields)),
"exceeded the maximum");
}
} // namespace
} // namespace netkat