diff -u -r a/third_party/ach/upstream/config.h b/third_party/ach/upstream/config.h
--- a/third_party/ach/upstream/config.h	2019-09-13 11:50:29.514523768 -0700
+++ b/third_party/ach/upstream/config.h	2019-09-13 11:45:38.835997041 -0700
@@ -0,0 +1,110 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the <ach.h> header file. */
+/* #undef HAVE_ACH_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <lcm/lcm.h> header file. */
+/* #undef HAVE_LCM_LCM_H */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Error Checking Mutexes */
+#define HAVE_MUTEX_ERROR_CHECK 1
+
+/* Priority Inheritance Mutex */
+#define HAVE_MUTEX_PRIORITY_INHERIT 1
+
+/* Robust Mutexes */
+#define HAVE_MUTEX_ROBUST 1
+
+/* If available, contains the Python version number currently in use. */
+/* #undef HAVE_PYTHON */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <tao/ORB.h> header file. */
+/* #undef HAVE_TAO_ORB_H */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "ach"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "ndantam@mines.edu"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "ach"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "ach 2.0.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "ach"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "2.0.0"
+
+/* Assume this is unsigned long */
+/* #undef PRIuPTR */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "2.0.0"
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to the equivalent of the C99 'restrict' keyword, or to
+   nothing if this is not supported.  Do not define if restrict is
+   supported directly.  */
+#define restrict __restrict
+/* Work around a bug in Sun C++: it does not support _Restrict or
+   __restrict__, even though the corresponding Sun C compiler ends up with
+   "#define restrict _Restrict" or "#define restrict __restrict__" in the
+   previous line.  Perhaps some future version of Sun C++ will work with
+   restrict; if so, hopefully it defines __RESTRICT like Sun C does.  */
+#if defined __SUNPRO_CC && !defined __RESTRICT
+# define _Restrict
+# define __restrict__
+#endif
diff -u -r a/third_party/ach/upstream/.gitignore b/third_party/ach/upstream/.gitignore
--- a/third_party/ach/upstream/.gitignore	2019-09-13 11:46:30.267028631 -0700
+++ b/third_party/ach/upstream/.gitignore	2019-09-13 11:45:38.827997192 -0700
@@ -22,7 +22,6 @@
 /Makefile
 /autoscan.log
 /config.guess
-/config.h
 /config.h.in
 /config.log
 /config.status
diff -u -r a/third_party/ach/upstream/include/ach/generic.h b/third_party/ach/upstream/include/ach/generic.h
--- a/third_party/ach/upstream/include/ach/generic.h	2019-09-13 11:46:30.279028405 -0700
+++ b/third_party/ach/upstream/include/ach/generic.h	2019-09-13 11:45:38.831997116 -0700
@@ -241,7 +241,10 @@
 } ach_get_opts_t;
 
 /**  maximum size of a channel name */
-#define ACH_CHAN_NAME_MAX 64ul
+// NOTE(rrishel) increase max size of channel name to 200 since topic
+// names can get quite long.
+//#define ACH_CHAN_NAME_MAX 64ul
+#define ACH_CHAN_NAME_MAX 200ul
 
 
 /** Function type to transfer data out of the channel.
diff -u -r a/third_party/ach/upstream/include/ach/impl_generic.h b/third_party/ach/upstream/include/ach/impl_generic.h
--- a/third_party/ach/upstream/include/ach/impl_generic.h	2019-09-13 11:46:30.279028405 -0700
+++ b/third_party/ach/upstream/include/ach/impl_generic.h	2019-09-13 11:45:38.831997116 -0700
@@ -137,9 +137,29 @@
         frame_cnt * frame_size + 3 * sizeof(uint64_t);
 }
 
-static void ach_create_counts( ach_header_t *shm, const char *name, size_t frame_cnt, size_t frame_size )
+/** Reset header to initial state.
+ *  Currently used to auto recover after corruption.
+ */
+static void ach_recover_header( ach_header_t *shm )
+{
+    shm->index_head = 0;
+    shm->index_free = shm->index_cnt;
+    shm->data_head = 0;
+    shm->data_free = shm->data_size;
+}
+
+/** Reset channel to initial state.
+ *  Currently used to auto recover after corruption.
+ */
+static void ach_recover_channel( ach_channel_t *chan )
 {
+    chan->seq_num = chan->shm->last_seq;
+    chan->next_index = 0;
+    chan->cancel = 0;
+}
 
+static void ach_create_counts( ach_header_t *shm, const char *name, size_t frame_cnt, size_t frame_size )
+{
     /* initialize counts */
     shm->index_cnt = frame_cnt;
     shm->index_head = 0;
@@ -235,6 +255,10 @@
  *
  *  \param [out] frame_size The number of bytes occupied by the frame in the channel
  *
+ *  \param [out] missed_frames The number of frames missed since last read from
+ *               channel. This will be populated if non-NULL and retval is
+ *               ACH_MISSED_FRAME.
+ *
  *  \param [in] timeout A timeout if ACH_O_WAIT is specified.  Take
  *              care that abstime is given in the correct clock.  The
  *              default is defined by ACH_DEFAULT_CLOCK.  In user-mode
@@ -246,13 +270,14 @@
  *  \return ACH_OK on success.
  */
 static enum ach_status ACH_WARN_UNUSED
-ach_xget(ach_channel_t * chan, ach_get_fun transfer, void *cx, void **pobj,
-         size_t * frame_size,
-         const struct timespec *timeout,
-         int options )
+ach_xget_ex(ach_channel_t * chan, ach_get_fun transfer, void *cx, void **pobj,
+            size_t * frame_size,
+            const struct timespec *timeout,
+            int *pmissed_frames,
+            int options )
 {
     struct ach_header *shm = chan->shm;
-    bool missed_frame = false;
+    int missed_frames = 0;
     enum ach_status retval = ACH_BUG;
     const bool o_wait = options & ACH_O_WAIT;
     const bool o_last = options & ACH_O_LAST;
@@ -294,9 +319,8 @@
             }
         }
 
-        if (index_ar[read_index].seq_num > chan->seq_num + 1) {
-            missed_frame = true;
-        }
+        /* record how many frames were missed since we last read */
+        missed_frames = index_ar[read_index].seq_num - (chan->seq_num + 1);
 
         /* read from the index */
         retval =
@@ -309,7 +333,56 @@
     /* relase read lock */
     if ( ACH_OK != (r=unrdlock(shm)) ) return r;
 
-    return (ACH_OK == retval && missed_frame) ? ACH_MISSED_FRAME : retval;
+    if (ACH_OK == retval && missed_frames > 0) {
+        if (pmissed_frames) {
+            *pmissed_frames = missed_frames;
+        }
+        return ACH_MISSED_FRAME;
+    } else {
+        return retval;
+    }
+}
+
+/** Pull a message from the channel.
+ *
+ *  \pre chan has been opened with ach_open()
+ *
+ *  Note that transfer() is called while holding the channel lock.
+ *  Expensive computation should thus be avoided during this call.
+ *
+ *  We could expose this function to reduce copying.  However, it
+ *  would be complicated and risky for kernel channels, requiring the
+ *  data buffer be mapped into userspace.  It could also deadlock
+ *  usermode channels if the transfer function exits the program.
+ *
+ *  \param [in,out] chan The previously opened channel handle
+ *
+ *  \param [in] transfer Function to transfer data out of the channel
+ *
+ *  \param [in,out] cx Context argument to transfer
+ *
+ *  \param [in,out] pobj Pointer to object pointer
+ *
+ *  \param [out] frame_size The number of bytes occupied by the frame in the channel
+ *
+ *  \param [in] timeout A timeout if ACH_O_WAIT is specified.  Take
+ *              care that abstime is given in the correct clock.  The
+ *              default is defined by ACH_DEFAULT_CLOCK.  In user-mode
+ *              this is an absolute timeout.  In kernel mode, it is a
+ *              relative timeout.
+ *
+ *  \param[in] options Option flags
+ *
+ *  \return ACH_OK on success.
+ */
+static enum ach_status ACH_WARN_UNUSED
+ach_xget(ach_channel_t * chan, ach_get_fun transfer, void *cx, void **pobj,
+         size_t * frame_size,
+         const struct timespec *timeout,
+         int options )
+{
+    /* backward-compatible wrapper */
+    return ach_xget_ex(chan, transfer, cx, pobj, frame_size, timeout, NULL/*missed_frames*/, options);
 }
 
 
@@ -374,6 +447,9 @@
         if( ACH_OK != r) return r;
     }
 
+    /* kill process if ach_test_set_kill_sig() was called */
+    ach_test_check_kill();
+
     /* find next index entry */
     idx = index_ar + shm->index_head;
 
diff -u -r a/third_party/ach/upstream/include/ach.h b/third_party/ach/upstream/include/ach.h
--- a/third_party/ach/upstream/include/ach.h	2019-09-13 11:46:30.275028481 -0700
+++ b/third_party/ach/upstream/include/ach.h	2019-09-13 11:45:38.831997116 -0700
@@ -246,6 +246,8 @@
                     uint64_t reserve_bits;           /**< reserve space for bit flags */
                     struct {
                         unsigned int lock_source : 1;   /**< if true, take the source lock when opening or fail */
+                        unsigned int recoverable : 1;   /**< if true, automatically reset ach_header
+                                                             when detecting corruption */
                     };
                 };
             };
@@ -267,6 +269,10 @@
     enum ach_status
     ach_attr_set_lock_source( ach_attr_t *attr, int lock_source );
 
+    /** Set recoverable value */
+    enum ach_status
+    ach_attr_set_recoverable( ach_attr_t *attr, int recoverable );
+
     /** Attributes to pass to ach_create.
      *
      *  Library users should access this struct through the provided
@@ -347,6 +353,10 @@
                 volatile sig_atomic_t cancel;          /**< cancel a waiting ach_get */
                 const struct ach_channel_vtab *vtab;   /**< virtual method table */
                 int fd_source_lock;                    /**< file descriptor for source lock */
+                struct {
+                    unsigned int recoverable : 1;      /**< if true, automatically reset ach_header
+                                                            when detecting corruption */
+                };
             };
             uint64_t reserved[16]; /**< Reserve space to compatibly add future options */
         };
@@ -415,6 +425,80 @@
     /** Pulls a message from the channel.
      *
      *  If a signal is delivered to a thread executing or waiting in
+     *  ach_get_ex, the thread will resume ach_get_ex after the signal
+     *  handler completes.
+     *
+     *  To interrupt a call to ach_get_ex before a new message is
+     *  received, use ach_cancel.
+     *
+     *  \pre chan has been opened with ach_open()
+     *
+     *  \post If buf is big enough to hold the next frame, buf
+     *        contains the data for the last frame and chan.seq_num is
+     *        set to the last frame.  If buf is too small to hold the
+     *        next frame, no side effects occur and ACH_OVERFLOW is
+     *        returned.  The seq_num field of chan will be set to the
+     *        latest sequence number (that of the gotten frame).
+     *
+     *  \bug Linux kernel channels will return ACH_OK when they should
+     *       return ACH_MISSED_FRAME.  The data is still retrieved,
+     *       but library clients are not notified of the skipped
+     *       messages.
+     *
+     *  \param[in,out] chan The previously opened channel handle
+     *
+     *  \param[out] buf Buffer to store data
+     *
+     *  \param[in] size Length of buffer in bytes
+     *
+     *  \param[out] frame_size The number of bytes copied to buf, or
+     *                         the size of the desired frame if buf is
+     *                         too small.
+     *
+     *  \param[in] abstime An absolute timeout if ::ACH_O_WAIT is
+     *                     specified.  Take care that abstime is given
+     *                     in the correct clock.  The default is
+     *                     defined by ACH_DEFAULT_CLOCK.
+     *
+     *  \param[out] missed_frames The number of frames missed since last get.
+     *                            Only populated if non-NULL and retval is
+     *                            ACH_MISSED_FRAME. copied to buf, or
+     *
+     *  \param[in] options Option flags
+     *
+     *  \return On success, returns ACH_OK.  Otherwise, returns an
+     *          error code indication the failure:
+     *
+     *  - ::ACH_OK: On success, returns ::ACH_OK and the location pointed
+     *            to by frame_size contains the number of bytes copied
+     *            to buf.
+     *
+     *  - ::ACH_MISSED_FRAME: If any frames were skipped in the buffer,
+     *                      the ::ACH_MISSED_FRAME may be returned.  The
+     *                      data is still copied and frame_size set as
+     *                      on ::ACH_OK.
+     *
+     *  - ::ACH_STALE_FRAMES
+     *  - ::ACH_TIMEOUT
+     *  - ::ACH_CANCELED
+     *  - ::ACH_OVERFLOW
+     *  - ::ACH_CORRUPT
+     *  - ::ACH_EINVAL
+     *  - ::ACH_EFAULT
+     *
+     * \sa ach_get_opts_t, ach_status
+     *
+     */
+    enum ach_status ACH_WARN_UNUSED
+    ach_get_ex( ach_channel_t *chan, void *buf, size_t size,
+                size_t *frame_size,
+                const struct timespec *ACH_RESTRICT abstime,
+                int *missed_frames,
+                int options );
+
+    /** Pulls a message from the channel.
+     *
+     *  If a signal is delivered to a thread executing or waiting in
      *  ach_get, the thread will resume ach_get after the signal
      *  handler completes.
      *
@@ -480,7 +564,6 @@
              size_t *frame_size,
              const struct timespec *ACH_RESTRICT abstime,
              int options );
-
     /** Copy a new message into the channel.
      *
      *  \pre chan has been opened with ach_open() and is large enough
@@ -576,6 +659,34 @@
     enum ach_status ACH_WARN_UNUSED
     ach_cancel( ach_channel_t *chan, const ach_cancel_attr_t *attr );
 
+    /** Return path to shmem file directory.
+     *  Example: "/dev/shm"
+     *
+     *  \param      attr      Options for resolving path.
+     *
+     *  \return non-NULL string on success.
+     */
+    const char* ACH_WARN_UNUSED
+    ach_prefix_filepath( const ach_attr_t *attr );
+
+    /** Return prefix for file names used in shmem file directory.
+     *  Example: "/achshm-"
+     *
+     *  \param      attr      Options for resolving path.
+     *
+     *  \return non-NULL string on success.
+     */
+    const char* ACH_WARN_UNUSED
+    ach_prefix_filename( const ach_attr_t *attr );
+
+    /** Set signal to send during ach_put to cause corrupt header */
+    void ACH_WARN_UNUSED
+    ach_test_set_kill( int sig );
+
+    /** If signal previously set by ach_test_set_kill() then send signal to self */
+    void ACH_WARN_UNUSED
+    ach_test_check_kill( void );
+
 #ifdef __cplusplus
 }
 #endif
diff -u -r a/third_party/ach/upstream/include/libach/vtab.h b/third_party/ach/upstream/include/libach/vtab.h
--- a/third_party/ach/upstream/include/libach/vtab.h	2019-09-13 11:46:30.279028405 -0700
+++ b/third_party/ach/upstream/include/libach/vtab.h	2019-09-13 11:45:38.831997116 -0700
@@ -77,13 +77,21 @@
     enum ach_status ACH_WARN_UNUSED
     (*put)(ach_channel_t*,const void *buf, size_t len);
 
-    /** Implementation of ach_flush() */
+    /** Implementation of ach_get() */
     enum ach_status ACH_WARN_UNUSED
     (*get)( ach_channel_t *chan, void *buf, size_t size,
             size_t *frame_size,
             const struct timespec *ACH_RESTRICT abstime,
             int options );
 
+    /** Implementation of ach_get_ex() */
+    enum ach_status ACH_WARN_UNUSED
+    (*get_ex)( ach_channel_t *chan, void *buf, size_t size,
+               size_t *frame_size,
+               const struct timespec *ACH_RESTRICT abstime,
+               int *missed_frames,
+               int options );
+
     /** Implementation of ach_cancel() */
     enum ach_status ACH_WARN_UNUSED
     (*cancel)( ach_channel_t *chan, const ach_cancel_attr_t *attr );
@@ -112,6 +120,14 @@
     enum ach_status ACH_WARN_UNUSED
     (*name_ok)( const char *name );
 
+    /** Get the directory prefix path. */
+    const char* ACH_WARN_UNUSED
+    (*prefix_filepath)( void );
+
+    /** Get the file name prefix. */
+    const char* ACH_WARN_UNUSED
+    (*prefix_filename)( void );
+
     /** The mapping for this vtab. */
     enum ach_map map;
 };
diff -u -r a/third_party/ach/upstream/include/libach_private.h b/third_party/ach/upstream/include/libach_private.h
--- a/third_party/ach/upstream/include/libach_private.h	2019-09-13 11:46:41.458817897 -0700
+++ b/third_party/ach/upstream/include/libach_private.h	2019-09-13 11:45:38.831997116 -0700
@@ -65,7 +65,9 @@
 /* DEBUG HELPERS */
 /*****************/
 
-#ifdef NDEBUG
+// NOTE(rrishel) Don't allow emitting debug output.
+//#ifdef NDEBUG
+#if 1
 
 #define IFDEBUG(test, x )
 #define ACH_ERRF( ... )
diff -u -r a/third_party/ach/upstream/src/libach.c b/third_party/ach/upstream/src/libach.c
--- a/third_party/ach/upstream/src/libach.c	2019-09-13 11:46:30.283028330 -0700
+++ b/third_party/ach/upstream/src/libach.c	2019-09-13 11:45:38.851996740 -0700
@@ -90,8 +90,13 @@
 
 static int bad_map( enum ach_map m )
 {
-    return (m < 0) ||
-        (m >= (sizeof(libach_vtabs) / sizeof(libach_vtabs[0])));
+    // NOTE(rrishel) Clang complains about this expression so we cast.
+    //   error: comparison of unsigned enum expression < 0 is always false
+    //   error: comparison of constant 4 with expression of type 'enum ach_map' is always false
+    /*return (m < 0) ||
+        (m >= (sizeof(libach_vtabs) / sizeof(libach_vtabs[0])));*/
+    return ((int)m < 0) ||
+           ((unsigned int)m >= (sizeof(libach_vtabs) / sizeof(libach_vtabs[0])));
 }
 
 const char *ach_result_to_string(ach_status_t result) {
@@ -274,10 +279,22 @@
         lockf( lockfd, F_ULOCK, 0 );
     }
     chan->fd_source_lock = lockfd;
+    /* Record whether we can automatically recover ach_header */
+    chan->recoverable = attr->recoverable;
     return r;
 }
 
 enum ach_status
+ach_get_ex( ach_channel_t *chan, void *buf, size_t size,
+            size_t *frame_size,
+            const struct timespec *ACH_RESTRICT timeout,
+            int *missed_frames,
+            int options )
+{
+    return chan->vtab->get_ex( chan, buf, size, frame_size, timeout, missed_frames, options );
+}
+
+enum ach_status
 ach_get( ach_channel_t *chan, void *buf, size_t size,
          size_t *frame_size,
          const struct timespec *ACH_RESTRICT timeout,
@@ -286,7 +303,6 @@
     return chan->vtab->get( chan, buf, size, frame_size, timeout, options );
 }
 
-
 enum ach_status
 ach_flush( ach_channel_t *chan )
 {
@@ -397,6 +413,45 @@
     return chan->vtab->cancel( chan, attr );
 }
 
+const char*
+ach_prefix_filepath( const ach_attr_t *attr ) {
+    if( NULL == attr ) attr = &default_ach_attr;
+    return libach_vtabs[attr->map]->prefix_filepath();
+}
+
+const char*
+ach_prefix_filename( const ach_attr_t *attr ) {
+    if( NULL == attr ) attr = &default_ach_attr;
+    return libach_vtabs[attr->map]->prefix_filename();
+}
+
+#ifdef HAVE_THREADS_H
+// First, try the C11 standard
+static _Thread_local int ach_test_kill_sig_var = 0;
+#elseif defined TLS
+// Next, try some Autoconf magic
+static TLS int ach_test_kill_sig_var = 0;
+#else
+// Otherwise, pray this works...
+static __thread int ach_test_kill_sig_var = 0;
+#endif
+
+void
+ach_test_set_kill( int sig ) {
+    ach_test_kill_sig_var = sig;
+}
+
+void
+ach_test_check_kill() {
+    // Send kill signal to ourself, if required.
+    if( ach_test_kill_sig_var != 0 ) {
+        // Sample the signal value and reset.
+        int sig = ach_test_kill_sig_var;
+        ach_test_kill_sig_var = 0;
+        kill( getpid(), sig );
+    }
+}
+
 #ifdef HAVE_THREADS_H
 // First, try the C11 standard
 static _Thread_local const char *ach_errstr_var;
@@ -504,3 +559,10 @@
     attr->lock_source = lock_source ? 1 : 0;
     return ACH_OK;
 }
+
+enum ach_status
+ach_attr_set_recoverable( ach_attr_t *attr, int recoverable )
+{
+    attr->recoverable = recoverable ? 1 : 0;
+    return ACH_OK;
+}
diff -u -r a/third_party/ach/upstream/src/libach_klinux.c b/third_party/ach/upstream/src/libach_klinux.c
--- a/third_party/ach/upstream/src/libach_klinux.c	2019-09-13 11:46:30.283028330 -0700
+++ b/third_party/ach/upstream/src/libach_klinux.c	2019-09-13 11:45:38.855996665 -0700
@@ -84,6 +84,17 @@
 #include <sys/ioctl.h>
 
 
+static const char*
+libach_prefix_filepath_klinux(void) {
+    return ACH_CHAR_CHAN_NAME_PREFIX_PATH;
+}
+
+
+static const char*
+libach_prefix_filename_klinux(void) {
+    return ACH_CHAR_CHAN_NAME_PREFIX_NAME;
+}
+
 
 static enum ach_status
 libach_filename_klinux( const char *name, char *buf, size_t n ) {
@@ -372,5 +383,7 @@
     .exists = libach_exists_klinux,
     .filename = libach_filename_klinux,
     .fd = libach_channel_fd_ok,
-    .name_ok = libach_name_ok
+    .name_ok = libach_name_ok,
+    .prefix_filepath = libach_prefix_filepath_klinux,
+    .prefix_filename = libach_prefix_filename_klinux
 };
diff -u -r a/third_party/ach/upstream/src/libach_posix.c b/third_party/ach/upstream/src/libach_posix.c
--- a/third_party/ach/upstream/src/libach_posix.c	2019-09-13 11:46:30.283028330 -0700
+++ b/third_party/ach/upstream/src/libach_posix.c	2019-09-13 11:45:38.851996740 -0700
@@ -149,6 +149,13 @@
 #endif /* HAVE_MUTEX_ROBUST */
     case 0: /* ok */
         if( chan->shm->sync.dirty ) {
+            if( chan->recoverable ) {
+                /* reset metadata so that we can recover channel */
+                ach_recover_header(chan->shm);
+                ach_recover_channel(chan);
+                chan->shm->sync.dirty = 0;
+                return ACH_OK; /* channel is now valid */
+            }
             pthread_mutex_unlock( &chan->shm->sync.mutex );
             ACH_ERRF("ach corrupt: channel is dirty\n");
             return ACH_CORRUPT;
@@ -236,6 +243,18 @@
 }
 
 
+static const char*
+libach_prefix_filepath_user(void) {
+    return ACH_SHM_CHAN_NAME_PREFIX_PATH;
+}
+
+
+static const char*
+libach_prefix_filename_user(void) {
+    return ACH_SHM_CHAN_NAME_PREFIX_NAME;
+}
+
+
 static enum ach_status
 libach_filename_user(const char* channame, char *buf, size_t n) {
     if (n < ACH_CHAN_NAME_MAX + 32) return ACH_BUG;
@@ -481,10 +500,11 @@
 }
 
 static enum ach_status
-libach_get_posix( ach_channel_t *chan, void *buf, size_t size,
-                  size_t *frame_size,
-                  const struct timespec *ACH_RESTRICT timeout,
-                  int options )
+libach_get_ex_posix( ach_channel_t *chan, void *buf, size_t size,
+                     size_t *frame_size,
+                     const struct timespec *ACH_RESTRICT timeout,
+                     int *missed_frames,
+                     int options )
 {
     const struct timespec *ptime;
     struct timespec ltime;
@@ -498,9 +518,18 @@
         /* timeout is absolute or NULL */
         ptime = timeout;
     }
-    return ach_xget( chan,
-                     get_fun_posix, &size, &buf,
-                     frame_size, ptime, options );
+    return ach_xget_ex( chan,
+                        get_fun_posix, &size, &buf,
+                        frame_size, ptime, missed_frames, options );
+}
+
+static enum ach_status
+libach_get_posix( ach_channel_t *chan, void *buf, size_t size,
+                  size_t *frame_size,
+                  const struct timespec *ACH_RESTRICT timeout,
+                  int options )
+{
+    return libach_get_ex_posix(chan, buf, size, frame_size, timeout, NULL/*missed_frames*/, options);
 }
 
 static enum ach_status
@@ -626,7 +655,13 @@
         chan->len = len;
         chan->shm = shm;
         chan->seq_num = 0;
-        chan->next_index = 1;
+        // NOTE(rrishel) The next_index needs to be initialized to 0 to prevent
+        // a buffer overflow when queue size is 1 and ach_get() is invoked when
+        // a message in the queue is constructed in a certain way.
+        //
+        // See: https://jira.zooxlabs.com/browse/SWAT-2584
+        //chan->next_index = 1;
+        chan->next_index = 0;
         chan->cancel = 0;
         chan->clock = clock;
     }
@@ -706,6 +741,12 @@
     return ACH_EINVAL;
 }
 
+static const char*
+libach_prefix_file_anon( void )
+{
+    return NULL;
+}
+
 static enum ach_status
 libach_unlink_anon( const char *name )
 {
@@ -728,13 +769,16 @@
     .flush = libach_flush_posix,
     .put = libach_put_posix,
     .get = libach_get_posix,
+    .get_ex = libach_get_ex_posix,
     .cancel = libach_cancel_posix,
     .close = libach_close_user,
     .unlink = libach_unlink_user,
     .exists = libach_exists_user,
     .filename = libach_filename_user,
     .fd = libach_channel_fd_notsup,
-    .name_ok = libach_name_ok
+    .name_ok = libach_name_ok,
+    .prefix_filepath = libach_prefix_filepath_user,
+    .prefix_filename = libach_prefix_filename_user
 };
 
 const struct ach_channel_vtab
@@ -745,11 +789,14 @@
     .flush = libach_flush_posix,
     .put = libach_put_posix,
     .get = libach_get_posix,
+    .get_ex = libach_get_ex_posix,
     .cancel = libach_cancel_posix,
     .close = libach_close_anon,
     .unlink = libach_unlink_anon,
     .exists = libach_exists_anon,
     .filename = libach_filename_anon,
     .fd = libach_channel_fd_notsup,
-    .name_ok = name_ok_always
+    .name_ok = name_ok_always,
+    .prefix_filepath = libach_prefix_file_anon,
+    .prefix_filename = libach_prefix_file_anon
 };
