Check validity of sender/fetcher before operating on it

Now if a user tries to query the channel or context from a sender or
fetcher that isn't valid, we will fail with a clearer error instead of
segfaulting. Note that this can happen when the user creates the sender
or fetcher using the TryMake* API and operates on the result without
explicitly checking its validity first.

Change-Id: Ie30fe3c21b602346c16561d6425d8e0f4186ec9f
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/events/event_loop.h b/aos/events/event_loop.h
index 809539a..9ad9f4f 100644
--- a/aos/events/event_loop.h
+++ b/aos/events/event_loop.h
@@ -274,7 +274,7 @@
   // Fetches the next message. Returns true if it fetched a new message.  This
   // method will only return messages sent after the Fetcher was created.
   bool FetchNext() {
-    const bool result = fetcher_->FetchNext();
+    const bool result = CHECK_NOTNULL(fetcher_)->FetchNext();
     if (result) {
       CheckChannelDataAlignment(fetcher_->context().data,
                                 fetcher_->context().size);
@@ -286,7 +286,7 @@
   // This will return the latest message regardless of if it was sent before or
   // after the fetcher was created.
   bool Fetch() {
-    const bool result = fetcher_->Fetch();
+    const bool result = CHECK_NOTNULL(fetcher_)->Fetch();
     if (result) {
       CheckChannelDataAlignment(fetcher_->context().data,
                                 fetcher_->context().size);
@@ -297,23 +297,25 @@
   // Returns a pointer to the contained flatbuffer, or nullptr if there is no
   // available message.
   const T *get() const {
-    return fetcher_->context().data != nullptr
+    return CHECK_NOTNULL(fetcher_)->context().data != nullptr
                ? flatbuffers::GetRoot<T>(
                      reinterpret_cast<const char *>(fetcher_->context().data))
                : nullptr;
   }
 
   // Returns the channel this fetcher uses
-  const Channel *channel() const { return fetcher_->channel(); }
+  const Channel *channel() const { return CHECK_NOTNULL(fetcher_)->channel(); }
 
   // Returns the context holding timestamps and other metadata about the
   // message.
-  const Context &context() const { return fetcher_->context(); }
+  const Context &context() const { return CHECK_NOTNULL(fetcher_)->context(); }
 
   const T &operator*() const { return *get(); }
   const T *operator->() const { return get(); }
 
-  // Returns true if this fetcher is valid and connected to a channel.
+  // Returns true if this fetcher is valid and connected to a channel. If you,
+  // e.g., are using TryMakeFetcher, then you must check valid() before
+  // attempting to use the Fetcher.
   bool valid() const { return static_cast<bool>(fetcher_); }
 
   // Copies the current flatbuffer into a FlatbufferVector.
@@ -346,7 +348,7 @@
     Builder(RawSender *sender, ChannelPreallocatedAllocator *allocator)
         : fbb_(allocator->size(), allocator),
           allocator_(allocator),
-          sender_(sender) {
+          sender_(CHECK_NOTNULL(sender)) {
       CheckChannelDataAlignment(allocator->data(), allocator->size());
       fbb_.ForceDefaults(true);
     }
@@ -414,10 +416,13 @@
   RawSender::Error SendDetached(FlatbufferDetachedBuffer<T> detached);
 
   // Equivalent to RawSender::CheckOk
-  void CheckOk(const RawSender::Error err) { sender_->CheckOk(err); };
+  void CheckOk(const RawSender::Error err) {
+    CHECK_NOTNULL(sender_)->CheckOk(err);
+  };
 
-  // Returns the name of the underlying queue.
-  const Channel *channel() const { return sender_->channel(); }
+  // Returns the name of the underlying queue, if valid.  You must check valid()
+  // first.
+  const Channel *channel() const { return CHECK_NOTNULL(sender_)->channel(); }
 
   // Returns true if the Sender is a valid Sender. If you, e.g., are using
   // TryMakeSender, then you must check valid() before attempting to use the
@@ -428,17 +433,19 @@
 
   // Returns the time_points that the last message was sent at.
   aos::monotonic_clock::time_point monotonic_sent_time() const {
-    return sender_->monotonic_sent_time();
+    return CHECK_NOTNULL(sender_)->monotonic_sent_time();
   }
   aos::realtime_clock::time_point realtime_sent_time() const {
-    return sender_->realtime_sent_time();
+    return CHECK_NOTNULL(sender_)->realtime_sent_time();
   }
   // Returns the queue index that this was sent with.
-  uint32_t sent_queue_index() const { return sender_->sent_queue_index(); }
+  uint32_t sent_queue_index() const {
+    return CHECK_NOTNULL(sender_)->sent_queue_index();
+  }
 
   // Returns the buffer index which MakeBuilder() will expose access to. This is
   // the buffer the caller can fill out.
-  int buffer_index() const { return sender_->buffer_index(); }
+  int buffer_index() const { return CHECK_NOTNULL(sender_)->buffer_index(); }
 
  private:
   friend class EventLoop;
@@ -576,7 +583,8 @@
   }
 
   // Like MakeFetcher, but returns an invalid fetcher if the given channel is
-  // not readable on this node or does not exist.
+  // not readable on this node or does not exist. You must check valid() on the
+  // Fetcher before using it.
   template <typename T>
   Fetcher<T> TryMakeFetcher(const std::string_view channel_name) {
     const Channel *const channel = GetChannel<T>(channel_name);
@@ -611,7 +619,8 @@
   }
 
   // Like MakeSender, but returns an invalid sender if the given channel is
-  // not sendable on this node or does not exist.
+  // not sendable on this node or does not exist. You must check valid() on the
+  // Sender before using it.
   template <typename T>
   Sender<T> TryMakeSender(const std::string_view channel_name) {
     const Channel *channel = GetChannel<T>(channel_name);