Merge "Move SearchDirectory into a common file"
diff --git a/aos/events/logging/log_cat.cc b/aos/events/logging/log_cat.cc
index 5d205a8..1168e6f 100644
--- a/aos/events/logging/log_cat.cc
+++ b/aos/events/logging/log_cat.cc
@@ -31,6 +31,9 @@
              "If positive, vectors longer than this will not be printed");
 DEFINE_bool(pretty, false,
             "If true, pretty print the messages on multiple lines");
+DEFINE_bool(print, true,
+            "If true, actually print the messages.  If false, discard them, "
+            "confirming they can be parsed.");
 
 // Print the flatbuffer out to stdout, both to remove the unnecessary cruft from
 // glog and to allow the user to readily redirect just the logged output
@@ -203,7 +206,9 @@
         printer_event_loop->MakeRawWatcher(
             channel, [channel, node_name, &builder](const aos::Context &context,
                                                     const void * /*message*/) {
-              PrintMessage(node_name, channel, context, &builder);
+              if (FLAGS_print) {
+                PrintMessage(node_name, channel, context, &builder);
+              }
             });
         found_channel = true;
       }
@@ -212,8 +217,10 @@
     // Print the messages from before the log start time.
     // TODO(austin): Sort between nodes too when it becomes annoying enough.
     for (const MessageInfo &message : messages_before_start) {
-      PrintMessage(message.node_name, message.fetcher->channel(),
-                   message.fetcher->context(), &builder);
+      if (FLAGS_print) {
+        PrintMessage(message.node_name, message.fetcher->channel(),
+                     message.fetcher->context(), &builder);
+      }
     }
     printer_event_loops.emplace_back(std::move(printer_event_loop));
 
diff --git a/aos/events/logging/logfile_utils.cc b/aos/events/logging/logfile_utils.cc
index 9316795..98527dc 100644
--- a/aos/events/logging/logfile_utils.cc
+++ b/aos/events/logging/logfile_utils.cc
@@ -362,7 +362,11 @@
   ResizeableBuffer data;
   data.resize(config_data.size());
   memcpy(data.data(), config_data.begin(), data.size());
-  return SizePrefixedFlatbufferVector<LogFileHeader>(std::move(data));
+  SizePrefixedFlatbufferVector<LogFileHeader> result(std::move(data));
+  if (!result.Verify()) {
+    return std::nullopt;
+  }
+  return result;
 }
 
 std::optional<SizePrefixedFlatbufferVector<MessageHeader>> ReadNthMessage(
@@ -382,7 +386,11 @@
   ResizeableBuffer data;
   data.resize(data_span.size());
   memcpy(data.data(), data_span.begin(), data.size());
-  return SizePrefixedFlatbufferVector<MessageHeader>(std::move(data));
+  SizePrefixedFlatbufferVector<MessageHeader> result(std::move(data));
+  if (!result.Verify()) {
+    return std::nullopt;
+  }
+  return result;
 }
 
 MessageReader::MessageReader(std::string_view filename)
diff --git a/aos/events/pong.cc b/aos/events/pong.cc
index f9f35c2..2f5a0a5 100644
--- a/aos/events/pong.cc
+++ b/aos/events/pong.cc
@@ -9,9 +9,7 @@
 DEFINE_string(config, "aos/events/pingpong_config.json", "Path to the config.");
 
 int main(int argc, char **argv) {
-  FLAGS_logtostderr = true;
-  google::InitGoogleLogging(argv[0]);
-  ::gflags::ParseCommandLineFlags(&argc, &argv, true);
+  aos::InitGoogle(&argc, &argv);
 
   aos::FlatbufferDetachedBuffer<aos::Configuration> config =
       aos::configuration::ReadConfig(FLAGS_config);
diff --git a/aos/events/simulated_event_loop.cc b/aos/events/simulated_event_loop.cc
index 4c28039..9c8bb09 100644
--- a/aos/events/simulated_event_loop.cc
+++ b/aos/events/simulated_event_loop.cc
@@ -856,7 +856,9 @@
     aos::monotonic_clock::time_point monotonic_remote_time,
     aos::realtime_clock::time_point realtime_remote_time,
     uint32_t remote_queue_index) {
-  CHECK_LE(size, this->size()) << ": Attempting to send too big a message.";
+  CHECK_LE(size, this->size())
+      << ": Attempting to send too big a message on "
+      << configuration::CleanedChannelToString(simulated_channel_->channel());
 
   // This is wasteful, but since flatbuffers fill from the back end of the
   // queue, we need it to be full sized.
diff --git a/third_party/flatbuffers/build_defs.bzl b/third_party/flatbuffers/build_defs.bzl
index f9c06f8..f496dab 100644
--- a/third_party/flatbuffers/build_defs.bzl
+++ b/third_party/flatbuffers/build_defs.bzl
@@ -22,6 +22,7 @@
     "--keep-prefix",
     "--cpp-std",
     "c++17",
+    "--require-explicit-ids",
     "--gen-mutable",
     "--reflect-names",
     "--cpp-ptr-type flatbuffers::unique_ptr",
diff --git a/third_party/flatbuffers/reflection/reflection.fbs b/third_party/flatbuffers/reflection/reflection.fbs
index d9e2dc4..61d2f0c 100644
--- a/third_party/flatbuffers/reflection/reflection.fbs
+++ b/third_party/flatbuffers/reflection/reflection.fbs
@@ -31,84 +31,84 @@
 }
 
 table Type {
-    base_type:BaseType;
-    element:BaseType = None;  // Only if base_type == Vector
-                              // or base_type == Array.
-    index:int = -1;  // If base_type == Object, index into "objects" below.
-                     // If base_type == Union, UnionType, or integral derived
-                     // from an enum, index into "enums" below.
-    fixed_length:uint16 = 0;  // Only if base_type == Array.
+    base_type:BaseType (id: 0);
+    element:BaseType = None (id: 1);  // Only if base_type == Vector
+                                      // or base_type == Array.
+    index:int = -1 (id: 2);  // If base_type == Object, index into "objects" below.
+                             // If base_type == Union, UnionType, or integral derived
+                             // from an enum, index into "enums" below.
+    fixed_length:uint16 = 0 (id: 3);  // Only if base_type == Array.
 }
 
 table KeyValue {
-    key:string (required, key);
-    value:string;
+    key:string (required, key, id: 0);
+    value:string (id: 1);
 }
 
 table EnumVal {
-    name:string (required);
-    value:long (key);
-    object:Object;  // Will be deprecated in favor of union_type in the future.
-    union_type:Type;
-    documentation:[string];
+    name:string (required, id: 0);
+    value:long (key, id: 1);
+    object:Object (id: 2);  // Will be deprecated in favor of union_type in the future.
+    union_type:Type (id: 3);
+    documentation:[string] (id: 4);
 }
 
 table Enum {
-    name:string (required, key);
-    values:[EnumVal] (required);  // In order of their values.
-    is_union:bool = false;
-    underlying_type:Type (required);
-    attributes:[KeyValue];
-    documentation:[string];
+    name:string (required, key, id: 0);
+    values:[EnumVal] (required, id: 1);  // In order of their values.
+    is_union:bool = false (id: 2);
+    underlying_type:Type (required, id: 3);
+    attributes:[KeyValue] (id: 4);
+    documentation:[string] (id: 5);
 }
 
 table Field {
-    name:string (required, key);
-    type:Type (required);
-    id:ushort;
-    offset:ushort;  // Offset into the vtable for tables, or into the struct.
-    default_integer:long = 0;
-    default_real:double = 0.0;
-    deprecated:bool = false;
-    required:bool = false;
-    key:bool = false;
-    attributes:[KeyValue];
-    documentation:[string];
-    optional:bool = false;
+    name:string (required, key, id: 0);
+    type:Type (required, id: 1);
+    id:ushort (id: 2);
+    offset:ushort (id: 3);  // Offset into the vtable for tables, or into the struct.
+    default_integer:long = 0 (id: 4);
+    default_real:double = 0.0 (id: 5);
+    deprecated:bool = false (id: 6);
+    required:bool = false (id: 7);
+    key:bool = false (id: 8);
+    attributes:[KeyValue] (id: 9);
+    documentation:[string] (id: 10);
+    optional:bool = false (id: 11);
 }
 
 table Object {  // Used for both tables and structs.
-    name:string (required, key);
-    fields:[Field] (required);  // Sorted.
-    is_struct:bool = false;
-    minalign:int;
-    bytesize:int;  // For structs.
-    attributes:[KeyValue];
-    documentation:[string];
+    name:string (required, key, id: 0);
+    fields:[Field] (required, id: 1);  // Sorted.
+    is_struct:bool = false (id: 2);
+    minalign:int (id: 3);
+    bytesize:int (id: 4);  // For structs.
+    attributes:[KeyValue] (id: 5);
+    documentation:[string] (id: 6);
 }
 
 table RPCCall {
-    name:string (required, key);
-    request:Object (required);      // must be a table (not a struct)
-    response:Object (required);     // must be a table (not a struct)
-    attributes:[KeyValue];
-    documentation:[string];
+    name:string (required, key, id: 0);
+    request:Object (required, id: 1);      // must be a table (not a struct)
+    response:Object (required, id: 2);     // must be a table (not a struct)
+    attributes:[KeyValue] (id: 3);
+    documentation:[string] (id: 4);
 }
 
 table Service {
-    name:string (required, key);
-    calls:[RPCCall];
-    attributes:[KeyValue];
-    documentation:[string];
+    name:string (required, key, id: 0);
+    calls:[RPCCall] (id: 1);
+    attributes:[KeyValue] (id: 2);
+    documentation:[string] (id: 3);
 }
 
 table Schema {
-    objects:[Object] (required);    // Sorted.
-    enums:[Enum] (required);        // Sorted.
-    file_ident:string;
-    file_ext:string;
-    root_table:Object;
-    services:[Service];             // Sorted.
+    objects:[Object] (required, id: 0);    // Sorted.
+    enums:[Enum] (required, id: 1);        // Sorted.
+    file_ident:string (id: 2);
+    file_ext:string (id: 3);
+    root_table:Object (id: 4);
+    services:[Service] (id: 5);             // Sorted.
 }
 
 root_type Schema;