You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by bc...@apache.org on 2026/09/04 23:30:53 UTC

(trafficserver) branch master updated: Make plugin API cleanup functions noexcept (#13590)

This is an automated email from the ASF dual-hosted git repository.

bryancall pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 6abce06f20 Make plugin API cleanup functions noexcept (#13590)
6abce06f20 is described below

commit 6abce06f2061d726c0edb91bc7a08e9a3a4083ab
Author: Bryan Call <bc...@apache.org>
AuthorDate: Fri Sep 4 16:30:47 2026 -0700

    Make plugin API cleanup functions noexcept (#13590)
    
    Exceptions have never been a supported error channel across the plugin API, but
    that contract was never written down, so one escaping into a plugin destructor
    terminated the process with no attribution. Annotate the 28 cleanup and teardown
    functions noexcept, each a function-try-block that aborts naming the function,
    and contain formatting failures inside ts::do_abort and _call_fatal, whose
    message building allocates. Mangled names are unchanged; the guide is updated.
---
 .../api/functions/TSActionCancel.en.rst            |   2 +-
 .../api/functions/TSContDataGet.en.rst             |   2 +-
 .../api/functions/TSContDataSet.en.rst             |   2 +-
 .../api/functions/TSContDestroy.en.rst             |   2 +-
 doc/developer-guide/api/functions/TSDebug.en.rst   |   2 +-
 .../api/functions/TSFetchCreate.en.rst             |   2 +-
 .../api/functions/TSHttpHdrDestroy.en.rst          |   2 +-
 .../api/functions/TSHttpParserCreate.en.rst        |   2 +-
 .../api/functions/TSIOBufferCreate.en.rst          |   2 +-
 .../api/functions/TSIOBufferReader.en.rst          |   6 +-
 .../api/functions/TSMBufferCreate.en.rst           |   4 +-
 .../api/functions/TSMimeHdrDestroy.en.rst          |   2 +-
 .../api/functions/TSMutexDestroy.en.rst            |   2 +-
 .../api/functions/TSMutexLock.en.rst               |   2 +-
 .../api/functions/TSMutexLockTry.en.rst            |   2 +-
 .../api/functions/TSMutexUnlock.en.rst             |   2 +-
 .../api/functions/TSSslServerContextCreate.en.rst  |   2 +-
 .../api/functions/TSTextLogObjectCreate.en.rst     |   4 +-
 .../api/functions/TSThreadDestroy.en.rst           |   2 +-
 .../api/functions/TSVConnAbort.en.rst              |   2 +-
 .../api/functions/TSVConnClose.en.rst              |   2 +-
 .../api/functions/TSVConnShutdown.en.rst           |   2 +-
 .../plugins/getting-started/index.en.rst           |  12 ++-
 include/ts/ts.h                                    |  68 ++++++-------
 include/tscpp/api/Logger.h                         |   2 +-
 include/tsutil/Assert.h                            |   2 +-
 include/tsutil/TsSharedMutex.h                     |  13 ++-
 plugins/esi/test/print_funcs.cc                    |   2 +-
 .../sslheaders/unit_tests/test_sslheaders.cc       |   2 +-
 plugins/header_rewrite/header_rewrite_test.cc      |   2 +-
 plugins/header_rewrite/matcher_tests.cc            |   4 +-
 .../multiplexer/unit_tests/test_chunk_decoder.cc   |   4 +-
 src/api/InkAPI.cc                                  | 109 ++++++++++++++-------
 src/api/InkIOCoreAPI.cc                            |  61 ++++++++----
 src/cripts/unit_tests/stub.cc                      |  10 +-
 src/iocore/cache/unit_tests/stub.cc                |   2 +-
 src/tsutil/Assert.cc                               |   9 +-
 37 files changed, 217 insertions(+), 137 deletions(-)

diff --git a/doc/developer-guide/api/functions/TSActionCancel.en.rst b/doc/developer-guide/api/functions/TSActionCancel.en.rst
index 1f8edd0530..abfb463fd2 100644
--- a/doc/developer-guide/api/functions/TSActionCancel.en.rst
+++ b/doc/developer-guide/api/functions/TSActionCancel.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
     #include <ts/ts.h>
 
-.. function:: void TSActionCancel(TSAction actionp)
+.. function:: void TSActionCancel(TSAction actionp) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSContDataGet.en.rst b/doc/developer-guide/api/functions/TSContDataGet.en.rst
index 7c0e75498e..fa9b83e49d 100644
--- a/doc/developer-guide/api/functions/TSContDataGet.en.rst
+++ b/doc/developer-guide/api/functions/TSContDataGet.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
     #include <ts/ts.h>
 
-.. function:: void* TSContDataGet(TSCont contp)
+.. function:: void* TSContDataGet(TSCont contp) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSContDataSet.en.rst b/doc/developer-guide/api/functions/TSContDataSet.en.rst
index 165fe30b97..0a6ccf98b1 100644
--- a/doc/developer-guide/api/functions/TSContDataSet.en.rst
+++ b/doc/developer-guide/api/functions/TSContDataSet.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
     #include <ts/ts.h>
 
-.. function:: void TSContDataSet(TSCont contp, void * data)
+.. function:: void TSContDataSet(TSCont contp, void * data) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSContDestroy.en.rst b/doc/developer-guide/api/functions/TSContDestroy.en.rst
index 12aa9bcfc6..e2b709043f 100644
--- a/doc/developer-guide/api/functions/TSContDestroy.en.rst
+++ b/doc/developer-guide/api/functions/TSContDestroy.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
     #include <ts/ts.h>
 
-.. function:: void TSContDestroy(TSCont contp)
+.. function:: void TSContDestroy(TSCont contp) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSDebug.en.rst b/doc/developer-guide/api/functions/TSDebug.en.rst
index d0b85efed8..551b38b8c9 100644
--- a/doc/developer-guide/api/functions/TSDebug.en.rst
+++ b/doc/developer-guide/api/functions/TSDebug.en.rst
@@ -33,7 +33,7 @@ Synopsis
 .. function:: void TSStatus(const char * format, ...)
 .. function:: void TSNote(const char * format, ...)
 .. function:: void TSWarning(const char * format, ...)
-.. function:: void TSError(const char * format, ...)
+.. function:: void TSError(const char * format, ...) noexcept
 .. function:: void TSFatal(const char * format, ...)
 .. function:: void TSAlert(const char * format, ...)
 .. function:: void TSEmergency(const char * format, ...)
diff --git a/doc/developer-guide/api/functions/TSFetchCreate.en.rst b/doc/developer-guide/api/functions/TSFetchCreate.en.rst
index 67d0602fea..fc31dc04f7 100644
--- a/doc/developer-guide/api/functions/TSFetchCreate.en.rst
+++ b/doc/developer-guide/api/functions/TSFetchCreate.en.rst
@@ -39,7 +39,7 @@ Synopsis
 .. function:: void TSFetchWriteData(TSFetchSM, const void *, size_t)
 .. function:: ssize_t TSFetchReadData(TSFetchSM, void *, size_t)
 .. function:: void TSFetchLaunch(TSFetchSM)
-.. function:: void TSFetchDestroy(TSFetchSM)
+.. function:: void TSFetchDestroy(TSFetchSM) noexcept
 .. function:: void TSFetchUserDataSet(TSFetchSM, void *)
 .. function:: void* TSFetchUserDataGet(TSFetchSM)
 .. function:: TSMBuffer TSFetchRespHdrMBufGet(TSFetchSM)
diff --git a/doc/developer-guide/api/functions/TSHttpHdrDestroy.en.rst b/doc/developer-guide/api/functions/TSHttpHdrDestroy.en.rst
index b40d6434ef..0bdbfc6de4 100644
--- a/doc/developer-guide/api/functions/TSHttpHdrDestroy.en.rst
+++ b/doc/developer-guide/api/functions/TSHttpHdrDestroy.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
     #include <ts/ts.h>
 
-.. function:: void TSHttpHdrDestroy(TSMBuffer bufp, TSMLoc offset)
+.. function:: void TSHttpHdrDestroy(TSMBuffer bufp, TSMLoc offset) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSHttpParserCreate.en.rst b/doc/developer-guide/api/functions/TSHttpParserCreate.en.rst
index 62f45994a1..a56b193ee1 100644
--- a/doc/developer-guide/api/functions/TSHttpParserCreate.en.rst
+++ b/doc/developer-guide/api/functions/TSHttpParserCreate.en.rst
@@ -33,7 +33,7 @@ Synopsis
 
 .. function:: TSHttpParser TSHttpParserCreate(void)
 .. function:: void TSHttpParserClear(TSHttpParser parser)
-.. function:: void TSHttpParserDestroy(TSHttpParser parser)
+.. function:: void TSHttpParserDestroy(TSHttpParser parser) noexcept
 .. function:: TSParseResult TSHttpHdrParseReq(TSHttpParser parser, TSMBuffer bufp, TSMLoc offset, const char ** start, const char * end)
 .. function:: TSParseResult TSHttpHdrParseResp(TSHttpParser parser, TSMBuffer bufp, TSMLoc offset, const char ** start, const char * end)
 
diff --git a/doc/developer-guide/api/functions/TSIOBufferCreate.en.rst b/doc/developer-guide/api/functions/TSIOBufferCreate.en.rst
index de5d0a35d5..f84727cdf2 100644
--- a/doc/developer-guide/api/functions/TSIOBufferCreate.en.rst
+++ b/doc/developer-guide/api/functions/TSIOBufferCreate.en.rst
@@ -33,7 +33,7 @@ Synopsis
 
 .. function:: TSIOBuffer TSIOBufferCreate(void)
 .. function:: TSIOBuffer TSIOBufferSizedCreate(TSIOBufferSizeIndex index)
-.. function:: void TSIOBufferDestroy(TSIOBuffer bufp)
+.. function:: void TSIOBufferDestroy(TSIOBuffer bufp) noexcept
 .. function:: int64_t TSIOBufferWrite(TSIOBuffer bufp, const void * buf, int64_t length)
 .. function:: void TSIOBufferProduce(TSIOBuffer bufp, int64_t nbytes)
 .. function:: int64_t TSIOBufferWaterMarkGet(TSIOBuffer bufp)
diff --git a/doc/developer-guide/api/functions/TSIOBufferReader.en.rst b/doc/developer-guide/api/functions/TSIOBufferReader.en.rst
index 54434fa2cc..44f44936d8 100644
--- a/doc/developer-guide/api/functions/TSIOBufferReader.en.rst
+++ b/doc/developer-guide/api/functions/TSIOBufferReader.en.rst
@@ -32,10 +32,10 @@ Synopsis
 
 .. function:: TSIOBufferReader TSIOBufferReaderAlloc(TSIOBuffer bufp)
 .. function:: TSIOBufferReader TSIOBufferReaderClone(TSIOBufferReader readerp)
-.. function:: void TSIOBufferReaderFree(TSIOBufferReader readerp)
-.. function:: void TSIOBufferReaderConsume(TSIOBufferReader readerp, int64_t nbytes)
+.. function:: void TSIOBufferReaderFree(TSIOBufferReader readerp) noexcept
+.. function:: void TSIOBufferReaderConsume(TSIOBufferReader readerp, int64_t nbytes) noexcept
 .. function:: TSIOBufferBlock TSIOBufferReaderStart(TSIOBufferReader readerp)
-.. function:: int64_t TSIOBufferReaderAvail(TSIOBufferReader readerp)
+.. function:: int64_t TSIOBufferReaderAvail(TSIOBufferReader readerp) noexcept
 .. function:: int64_t TSIOBufferReaderCopy(TSIOBufferReader reader, void * buf, int64_t length)
 
 Description
diff --git a/doc/developer-guide/api/functions/TSMBufferCreate.en.rst b/doc/developer-guide/api/functions/TSMBufferCreate.en.rst
index 36bdf0d8a5..4469965d6d 100644
--- a/doc/developer-guide/api/functions/TSMBufferCreate.en.rst
+++ b/doc/developer-guide/api/functions/TSMBufferCreate.en.rst
@@ -30,8 +30,8 @@ Synopsis
     #include <ts/ts.h>
 
 .. function:: TSMBuffer TSMBufferCreate(void)
-.. function:: TSReturnCode TSMBufferDestroy(TSMBuffer bufp)
-.. function:: TSReturnCode TSHandleMLocRelease(TSMBuffer bufp, TSMLoc parent, TSMLoc mloc)
+.. function:: TSReturnCode TSMBufferDestroy(TSMBuffer bufp) noexcept
+.. function:: TSReturnCode TSHandleMLocRelease(TSMBuffer bufp, TSMLoc parent, TSMLoc mloc) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSMimeHdrDestroy.en.rst b/doc/developer-guide/api/functions/TSMimeHdrDestroy.en.rst
index 000f58dc9d..f1a262db4d 100644
--- a/doc/developer-guide/api/functions/TSMimeHdrDestroy.en.rst
+++ b/doc/developer-guide/api/functions/TSMimeHdrDestroy.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
     #include <ts/ts.h>
 
-.. function:: TSReturnCode TSMimeHdrDestroy(TSMBuffer bufp, TSMLoc offset)
+.. function:: TSReturnCode TSMimeHdrDestroy(TSMBuffer bufp, TSMLoc offset) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSMutexDestroy.en.rst b/doc/developer-guide/api/functions/TSMutexDestroy.en.rst
index 11de6b57b8..58cbca8e63 100644
--- a/doc/developer-guide/api/functions/TSMutexDestroy.en.rst
+++ b/doc/developer-guide/api/functions/TSMutexDestroy.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
     #include <ts/ts.h>
 
-.. function:: void TSMutexDestroy(TSMutex mutexp)
+.. function:: void TSMutexDestroy(TSMutex mutexp) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSMutexLock.en.rst b/doc/developer-guide/api/functions/TSMutexLock.en.rst
index d7cd24af55..6540c414dc 100644
--- a/doc/developer-guide/api/functions/TSMutexLock.en.rst
+++ b/doc/developer-guide/api/functions/TSMutexLock.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
     #include <ts/ts.h>
 
-.. function:: void TSMutexLock(TSMutex mutexp)
+.. function:: void TSMutexLock(TSMutex mutexp) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSMutexLockTry.en.rst b/doc/developer-guide/api/functions/TSMutexLockTry.en.rst
index be8754efb7..54dc63e25c 100644
--- a/doc/developer-guide/api/functions/TSMutexLockTry.en.rst
+++ b/doc/developer-guide/api/functions/TSMutexLockTry.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
     #include <ts/ts.h>
 
-.. function:: TSReturnCode TSMutexLockTry(TSMutex mutexp)
+.. function:: TSReturnCode TSMutexLockTry(TSMutex mutexp) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSMutexUnlock.en.rst b/doc/developer-guide/api/functions/TSMutexUnlock.en.rst
index 27484f83e3..cd0d9774b0 100644
--- a/doc/developer-guide/api/functions/TSMutexUnlock.en.rst
+++ b/doc/developer-guide/api/functions/TSMutexUnlock.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
     #include <ts/ts.h>
 
-.. function:: void TSMutexUnlock(TSMutex mutexp)
+.. function:: void TSMutexUnlock(TSMutex mutexp) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSSslServerContextCreate.en.rst b/doc/developer-guide/api/functions/TSSslServerContextCreate.en.rst
index 8ded24ad06..e162cd999f 100644
--- a/doc/developer-guide/api/functions/TSSslServerContextCreate.en.rst
+++ b/doc/developer-guide/api/functions/TSSslServerContextCreate.en.rst
@@ -31,7 +31,7 @@ Synopsis
     #include <ts/ts.h>
 
 .. function:: TSSslContext TSSslServerContextCreate(TSSslX509 *cert, char *certname)
-.. function:: void TSSslContextDestroy(TSSslContext ctx)
+.. function:: void TSSslContextDestroy(TSSslContext ctx) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSTextLogObjectCreate.en.rst b/doc/developer-guide/api/functions/TSTextLogObjectCreate.en.rst
index ceacafe2ed..d2aeaa0405 100644
--- a/doc/developer-guide/api/functions/TSTextLogObjectCreate.en.rst
+++ b/doc/developer-guide/api/functions/TSTextLogObjectCreate.en.rst
@@ -33,8 +33,8 @@ Synopsis
 
 .. function:: TSReturnCode TSTextLogObjectCreate(const char * filename, int mode, TSTextLogObject * new_log_obj)
 .. function:: TSReturnCode TSTextLogObjectWrite(TSTextLogObject the_object, const char * format, ...)
-.. function:: void TSTextLogObjectFlush(TSTextLogObject the_object)
-.. function:: TSReturnCode TSTextLogObjectDestroy(TSTextLogObject the_object)
+.. function:: void TSTextLogObjectFlush(TSTextLogObject the_object) noexcept
+.. function:: TSReturnCode TSTextLogObjectDestroy(TSTextLogObject the_object) noexcept
 .. function:: void TSTextLogObjectHeaderSet(TSTextLogObject the_object, const char * header)
 .. function:: TSReturnCode TSTextLogObjectRollingEnabledSet(TSTextLogObject the_object, int rolling_enabled)
 .. function:: void TSTextLogObjectRollingIntervalSecSet(TSTextLogObject the_object, int rolling_interval_sec)
diff --git a/doc/developer-guide/api/functions/TSThreadDestroy.en.rst b/doc/developer-guide/api/functions/TSThreadDestroy.en.rst
index c0a9b42528..76e8680769 100644
--- a/doc/developer-guide/api/functions/TSThreadDestroy.en.rst
+++ b/doc/developer-guide/api/functions/TSThreadDestroy.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
     #include <ts/ts.h>
 
-.. function:: void TSThreadDestroy(TSThread thread)
+.. function:: void TSThreadDestroy(TSThread thread) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSVConnAbort.en.rst b/doc/developer-guide/api/functions/TSVConnAbort.en.rst
index afd9547bc8..1380618414 100644
--- a/doc/developer-guide/api/functions/TSVConnAbort.en.rst
+++ b/doc/developer-guide/api/functions/TSVConnAbort.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
     #include <ts/ts.h>
 
-.. function:: void TSVConnAbort(TSVConn connp, int error)
+.. function:: void TSVConnAbort(TSVConn connp, int error) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSVConnClose.en.rst b/doc/developer-guide/api/functions/TSVConnClose.en.rst
index 0e2570ae0f..8363328d12 100644
--- a/doc/developer-guide/api/functions/TSVConnClose.en.rst
+++ b/doc/developer-guide/api/functions/TSVConnClose.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
     #include <ts/ts.h>
 
-.. function:: void TSVConnClose(TSVConn connp)
+.. function:: void TSVConnClose(TSVConn connp) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/api/functions/TSVConnShutdown.en.rst b/doc/developer-guide/api/functions/TSVConnShutdown.en.rst
index 1eda060da6..5370ab6be2 100644
--- a/doc/developer-guide/api/functions/TSVConnShutdown.en.rst
+++ b/doc/developer-guide/api/functions/TSVConnShutdown.en.rst
@@ -28,7 +28,7 @@ Synopsis
 
     #include <ts/ts.h>
 
-.. function:: void TSVConnShutdown(TSVConn connp, int read, int write)
+.. function:: void TSVConnShutdown(TSVConn connp, int read, int write) noexcept
 
 Description
 ===========
diff --git a/doc/developer-guide/plugins/getting-started/index.en.rst b/doc/developer-guide/plugins/getting-started/index.en.rst
index aaf577ba60..35008e8408 100644
--- a/doc/developer-guide/plugins/getting-started/index.en.rst
+++ b/doc/developer-guide/plugins/getting-started/index.en.rst
@@ -33,7 +33,17 @@ Getting Started
 The Traffic Server API enables you to create plugins, using the C++
 programming language, that customize the behavior of your Traffic Server
 installation. (Your plugin may not work properly if you use a version of C++
-older than C++17.) This chapter contains the following sections:
+older than C++17.)
+
+C++ exceptions are not a supported error channel across the plugin API. API
+functions report failure through their return values, and a plugin must not
+allow one of its own exceptions to propagate into Traffic Server (for example
+out of a continuation handler). API functions that plugins commonly call
+during cleanup are declared ``noexcept``; if an internal error would otherwise
+escape such a call as an exception, Traffic Server aborts with a message
+naming the function rather than raising an exception in the plugin.
+
+This chapter contains the following sections:
 
 -  `Understanding Traffic Server Plugins`_ -- a brief introduction to plugins.
 
diff --git a/include/ts/ts.h b/include/ts/ts.h
index 31ff0379b5..80481ed283 100644
--- a/include/ts/ts.h
+++ b/include/ts/ts.h
@@ -85,7 +85,7 @@ TSstrndup(const char *p, int64_t n)
     @param mloc location of the handle to be released.
 
  */
-TSReturnCode TSHandleMLocRelease(TSMBuffer bufp, TSMLoc parent, TSMLoc mloc);
+TSReturnCode TSHandleMLocRelease(TSMBuffer bufp, TSMLoc parent, TSMLoc mloc) noexcept;
 
 /* --------------------------------------------------------------------------
    Install and plugin locations */
@@ -297,13 +297,13 @@ char *TSfgets(TSFile filep, char *buf, size_t length);
     immediate attention.
 
 */
-void TSStatus(const char *fmt, ...) TS_PRINTFLIKE(1, 2);    // Log information
-void TSNote(const char *fmt, ...) TS_PRINTFLIKE(1, 2);      // Log significant information
-void TSWarning(const char *fmt, ...) TS_PRINTFLIKE(1, 2);   // Log concerning information
-void TSError(const char *fmt, ...) TS_PRINTFLIKE(1, 2);     // Log operational failure, fail CI
-void TSFatal(const char *fmt, ...) TS_PRINTFLIKE(1, 2);     // Log recoverable crash, fail CI, exit & restart
-void TSAlert(const char *fmt, ...) TS_PRINTFLIKE(1, 2);     // Log recoverable crash, fail CI, exit & restart, Ops attention
-void TSEmergency(const char *fmt, ...) TS_PRINTFLIKE(1, 2); // Log unrecoverable crash, fail CI, exit, Ops attention
+void TSStatus(const char *fmt, ...) TS_PRINTFLIKE(1, 2);         // Log information
+void TSNote(const char *fmt, ...) TS_PRINTFLIKE(1, 2);           // Log significant information
+void TSWarning(const char *fmt, ...) TS_PRINTFLIKE(1, 2);        // Log concerning information
+void TSError(const char *fmt, ...) noexcept TS_PRINTFLIKE(1, 2); // Log operational failure, fail CI
+void TSFatal(const char *fmt, ...) TS_PRINTFLIKE(1, 2);          // Log recoverable crash, fail CI, exit & restart
+void TSAlert(const char *fmt, ...) TS_PRINTFLIKE(1, 2);          // Log recoverable crash, fail CI, exit & restart, Ops attention
+void TSEmergency(const char *fmt, ...) TS_PRINTFLIKE(1, 2);      // Log unrecoverable crash, fail CI, exit, Ops attention
 
 /* --------------------------------------------------------------------------
    Assertions */
@@ -331,7 +331,7 @@ TSMBuffer TSMBufferCreate(void);
     @param bufp marshal buffer to be destroyed.
 
  */
-TSReturnCode TSMBufferDestroy(TSMBuffer bufp);
+TSReturnCode TSMBufferDestroy(TSMBuffer bufp) noexcept;
 
 /* --------------------------------------------------------------------------
    URLs */
@@ -817,7 +817,7 @@ TSReturnCode TSMimeHdrCreate(TSMBuffer bufp, TSMLoc *locp);
     @param offset location of the MIME header.
 
  */
-TSReturnCode TSMimeHdrDestroy(TSMBuffer bufp, TSMLoc offset);
+TSReturnCode TSMimeHdrDestroy(TSMBuffer bufp, TSMLoc offset) noexcept;
 
 /**
     Copies a specified MIME header to a specified marshal buffer,
@@ -1059,7 +1059,7 @@ TSReturnCode TSMimeFormatDate(time_t const value_time, char *const value_str, in
    HTTP headers */
 TSHttpParser TSHttpParserCreate(void);
 void         TSHttpParserClear(TSHttpParser parser);
-void         TSHttpParserDestroy(TSHttpParser parser);
+void         TSHttpParserDestroy(TSHttpParser parser) noexcept;
 
 /**
     Parses an HTTP request header. The HTTP header must have already
@@ -1102,7 +1102,7 @@ TSMLoc TSHttpHdrCreate(TSMBuffer bufp);
     call to TSHandleMLocRelease().
 
  */
-void TSHttpHdrDestroy(TSMBuffer bufp, TSMLoc offset);
+void TSHttpHdrDestroy(TSMBuffer bufp, TSMLoc offset) noexcept;
 
 TSReturnCode TSHttpHdrClone(TSMBuffer dest_bufp, TSMBuffer src_bufp, TSMLoc src_hdr, TSMLoc *locp);
 
@@ -1154,19 +1154,19 @@ const char  *TSHttpHdrReasonLookup(TSHttpStatus status);
    Threads */
 TSThread      TSThreadCreate(TSThreadFunc func, void *data);
 TSThread      TSThreadInit(void);
-void          TSThreadDestroy(TSThread thread);
-void          TSThreadWait(TSThread thread);
+void          TSThreadDestroy(TSThread thread) noexcept;
+void          TSThreadWait(TSThread thread) noexcept;
 TSThread      TSThreadSelf(void);
 TSEventThread TSEventThreadSelf(void);
 
 /* --------------------------------------------------------------------------
    Mutexes */
 TSMutex      TSMutexCreate(void);
-void         TSMutexDestroy(TSMutex mutexp);
-void         TSMutexLock(TSMutex mutexp);
-TSReturnCode TSMutexLockTry(TSMutex mutexp);
+void         TSMutexDestroy(TSMutex mutexp) noexcept;
+void         TSMutexLock(TSMutex mutexp) noexcept;
+TSReturnCode TSMutexLockTry(TSMutex mutexp) noexcept;
 
-void TSMutexUnlock(TSMutex mutexp);
+void TSMutexUnlock(TSMutex mutexp) noexcept;
 
 /** Scoped lock guard for a @c TSMutex.
 
@@ -1231,7 +1231,7 @@ TSReturnCode TSCacheKeyPinnedSet(TSCacheKey key, time_t pin_in_cache);
     @param key to be destroyed.
 
  */
-TSReturnCode TSCacheKeyDestroy(TSCacheKey key);
+TSReturnCode TSCacheKeyDestroy(TSCacheKey key) noexcept;
 
 /* --------------------------------------------------------------------------
    cache url */
@@ -1361,9 +1361,9 @@ TSHRTime TShrtime(void);
 /* --------------------------------------------------------------------------
    Continuations */
 TSCont                TSContCreate(TSEventFunc funcp, TSMutex mutexp);
-void                  TSContDestroy(TSCont contp);
-void                  TSContDataSet(TSCont contp, void *data);
-void                 *TSContDataGet(TSCont contp);
+void                  TSContDestroy(TSCont contp) noexcept;
+void                  TSContDataSet(TSCont contp, void *data) noexcept;
+void                 *TSContDataGet(TSCont contp) noexcept;
 TSAction              TSContScheduleOnPool(TSCont contp, TSHRTime timeout, TSThreadPool tp);
 TSAction              TSContScheduleOnThread(TSCont contp, TSHRTime timeout, TSEventThread ethread);
 std::vector<TSAction> TSContScheduleOnEntirePool(TSCont contp, TSHRTime timeout, TSThreadPool tp);
@@ -1433,7 +1433,7 @@ TSReturnCode TSSslSecretUpdate(const char *secret_name, int secret_name_length);
 
 /* Create a new SSL context based on the settings in records.yaml */
 TSSslContext TSSslServerContextCreate(TSSslX509 cert, const char *certname, const char *rsp_file);
-void         TSSslContextDestroy(TSSslContext ctx);
+void         TSSslContextDestroy(TSSslContext ctx) noexcept;
 TSReturnCode TSSslTicketKeyUpdate(char *ticketData, int ticketDataLen);
 TSAcceptor   TSAcceptorGet(TSVConn sslp);
 TSAcceptor   TSAcceptorGetbyID(int ID);
@@ -2150,7 +2150,7 @@ void TSFetchLaunch(TSFetchSM fetch_sm);
  *
  * @param fetch_sm: returned value of TSFetchCreate().
  */
-void TSFetchDestroy(TSFetchSM fetch_sm);
+void TSFetchDestroy(TSFetchSM fetch_sm) noexcept;
 
 /*
  * Set user-defined data in FetchSM
@@ -2185,7 +2185,7 @@ void         TSHttpAltInfoQualitySet(TSHttpAltInfo infop, float quality);
 
 /* --------------------------------------------------------------------------
    Actions */
-void TSActionCancel(TSAction actionp);
+void TSActionCancel(TSAction actionp) noexcept;
 int  TSActionDone(TSAction actionp);
 
 /* --------------------------------------------------------------------------
@@ -2196,9 +2196,9 @@ int   TSVConnClosedGet(TSVConn connp);
 
 TSVIO TSVConnRead(TSVConn connp, TSCont contp, TSIOBuffer bufp, int64_t nbytes);
 TSVIO TSVConnWrite(TSVConn connp, TSCont contp, TSIOBufferReader readerp, int64_t nbytes);
-void  TSVConnClose(TSVConn connp);
-void  TSVConnAbort(TSVConn connp, int error);
-void  TSVConnShutdown(TSVConn connp, int read, int write);
+void  TSVConnClose(TSVConn connp) noexcept;
+void  TSVConnAbort(TSVConn connp, int error) noexcept;
+void  TSVConnShutdown(TSVConn connp, int read, int write) noexcept;
 
 /* --------------------------------------------------------------------------
    Cache VConnections */
@@ -2492,7 +2492,7 @@ int64_t TSIOBufferWaterMarkGet(TSIOBuffer bufp);
  */
 void TSIOBufferWaterMarkSet(TSIOBuffer bufp, int64_t water_mark);
 
-void            TSIOBufferDestroy(TSIOBuffer bufp);
+void            TSIOBufferDestroy(TSIOBuffer bufp) noexcept;
 TSIOBufferBlock TSIOBufferStart(TSIOBuffer bufp);
 int64_t         TSIOBufferCopy(TSIOBuffer bufp, TSIOBufferReader readerp, int64_t length, int64_t offset);
 
@@ -2519,10 +2519,10 @@ int64_t         TSIOBufferBlockWriteAvail(TSIOBufferBlock blockp);
 
 TSIOBufferReader TSIOBufferReaderAlloc(TSIOBuffer bufp);
 TSIOBufferReader TSIOBufferReaderClone(TSIOBufferReader readerp);
-void             TSIOBufferReaderFree(TSIOBufferReader readerp);
+void             TSIOBufferReaderFree(TSIOBufferReader readerp) noexcept;
 TSIOBufferBlock  TSIOBufferReaderStart(TSIOBufferReader readerp);
-void             TSIOBufferReaderConsume(TSIOBufferReader readerp, int64_t nbytes);
-int64_t          TSIOBufferReaderAvail(TSIOBufferReader readerp);
+void             TSIOBufferReaderConsume(TSIOBufferReader readerp, int64_t nbytes) noexcept;
+int64_t          TSIOBufferReaderAvail(TSIOBufferReader readerp) noexcept;
 int64_t          TSIOBufferReaderCopy(TSIOBufferReader readerp, void *buf, int64_t length);
 
 struct sockaddr const *TSNetVConnLocalAddrGet(TSVConn vc);
@@ -2702,7 +2702,7 @@ TSReturnCode TSTextLogObjectWrite(TSTextLogObject the_object, const char *format
       flushed.
 
  */
-void TSTextLogObjectFlush(TSTextLogObject the_object);
+void TSTextLogObjectFlush(TSTextLogObject the_object) noexcept;
 
 /**
     Destroys a log object and releases the memory allocated to it.
@@ -2711,7 +2711,7 @@ void TSTextLogObjectFlush(TSTextLogObject the_object);
     @param  the_object custom log to be destroyed.
 
  */
-TSReturnCode TSTextLogObjectDestroy(TSTextLogObject the_object);
+TSReturnCode TSTextLogObjectDestroy(TSTextLogObject the_object) noexcept;
 
 /**
     Set log header.
diff --git a/include/tscpp/api/Logger.h b/include/tscpp/api/Logger.h
index 049262422c..a7cf7608cc 100644
--- a/include/tscpp/api/Logger.h
+++ b/include/tscpp/api/Logger.h
@@ -88,7 +88,7 @@
  *
  * @private
  */
-void TSError(const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(1, 2);
+void TSError(const char *fmt, ...) noexcept ATSCPPAPI_PRINTFLIKE(1, 2);
 
 // This is weird, but see the following:
 //   http://stackoverflow.com/questions/5641427/how-to-make-preprocessor-generate-a-string-for-line-keyword
diff --git a/include/tsutil/Assert.h b/include/tsutil/Assert.h
index a536e42640..2903c754b5 100644
--- a/include/tsutil/Assert.h
+++ b/include/tsutil/Assert.h
@@ -28,7 +28,7 @@
 namespace ts
 {
 
-void do_abort(const SourceLocation &loc, const char *expr, const char *message = nullptr);
+[[noreturn]] void do_abort(const SourceLocation &loc, const char *expr, const char *message = nullptr) noexcept;
 
 }
 
diff --git a/include/tsutil/TsSharedMutex.h b/include/tsutil/TsSharedMutex.h
index bf09885040..76903c6825 100644
--- a/include/tsutil/TsSharedMutex.h
+++ b/include/tsutil/TsSharedMutex.h
@@ -24,6 +24,8 @@
 
 #pragma once
 
+#include <cstdio>
+#include <cstdlib>
 #include <pthread.h>
 #include "tsutil/Strerror.h"
 #include "tsutil/Assert.h"
@@ -172,10 +174,15 @@ private:
   pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER;
 #endif
 
-  static void
-  _call_fatal(char const *func_name, void *ptr, int errnum)
-  {
+  [[noreturn]] static void
+  _call_fatal(char const *func_name, void *ptr, int errnum) noexcept
+  try {
     fatal_error("{}({}) failed: {} ({})", func_name, ptr, Strerror(errnum).c_str(), errnum);
+  } catch (...) {
+    // Formatting the message can throw (it allocates); abort with a minimal
+    // breadcrumb rather than let an exception escape into a noexcept destructor.
+    fprintf(stderr, "shared_mutex: %s failed (%d); abort message formatting threw\n", func_name, errnum);
+    std::abort();
   }
 
   // In debug builds, make sure shared vs. exclusive locks and unlocks are properly paired.
diff --git a/plugins/esi/test/print_funcs.cc b/plugins/esi/test/print_funcs.cc
index d73b973d65..5cff08abf0 100644
--- a/plugins/esi/test/print_funcs.cc
+++ b/plugins/esi/test/print_funcs.cc
@@ -102,7 +102,7 @@ DbgCtl::_override_global_on()
 }
 
 void
-TSError(const char *fmt, ...)
+TSError(const char *fmt, ...) noexcept
 {
   char    buf[LINE_SIZE];
   va_list ap;
diff --git a/plugins/experimental/sslheaders/unit_tests/test_sslheaders.cc b/plugins/experimental/sslheaders/unit_tests/test_sslheaders.cc
index 5d967688d6..f6400a5bf5 100644
--- a/plugins/experimental/sslheaders/unit_tests/test_sslheaders.cc
+++ b/plugins/experimental/sslheaders/unit_tests/test_sslheaders.cc
@@ -41,7 +41,7 @@ DbgCtl::print(const char *tag, char const * /* file */, char const * /* function
 }
 
 void
-TSError(const char *fmt, ...)
+TSError(const char *fmt, ...) noexcept
 {
   va_list args;
 
diff --git a/plugins/header_rewrite/header_rewrite_test.cc b/plugins/header_rewrite/header_rewrite_test.cc
index cb166fd704..7ec83230a3 100644
--- a/plugins/header_rewrite/header_rewrite_test.cc
+++ b/plugins/header_rewrite/header_rewrite_test.cc
@@ -43,7 +43,7 @@ const char PLUGIN_NAME_DBG[] = "TEST_dbg_header_rewrite";
 } // namespace header_rewrite_ns
 
 void
-TSError(const char *fmt, ...)
+TSError(const char *fmt, ...) noexcept
 {
   va_list args;
 
diff --git a/plugins/header_rewrite/matcher_tests.cc b/plugins/header_rewrite/matcher_tests.cc
index 83c8c1bc6a..f943aca814 100644
--- a/plugins/header_rewrite/matcher_tests.cc
+++ b/plugins/header_rewrite/matcher_tests.cc
@@ -31,7 +31,7 @@ _TSAssert(const char *, const char *, int)
 }
 
 void
-TSError(const char *fmt, ...)
+TSError(const char *fmt, ...) noexcept
 {
   va_list args;
 
@@ -48,7 +48,7 @@ TSHttpHdrStatusGet(TSMBuffer, TSMLoc)
 }
 
 TSReturnCode
-TSHandleMLocRelease(TSMBuffer, TSMLoc, TSMLoc)
+TSHandleMLocRelease(TSMBuffer, TSMLoc, TSMLoc) noexcept
 {
   return TS_SUCCESS;
 }
diff --git a/plugins/multiplexer/unit_tests/test_chunk_decoder.cc b/plugins/multiplexer/unit_tests/test_chunk_decoder.cc
index 04ff18b81f..a342efa5b0 100644
--- a/plugins/multiplexer/unit_tests/test_chunk_decoder.cc
+++ b/plugins/multiplexer/unit_tests/test_chunk_decoder.cc
@@ -74,14 +74,14 @@ TSIOBufferReaderStart(TSIOBufferReader /* readerp ATS_UNUSED */)
 }
 
 void
-TSIOBufferReaderConsume(TSIOBufferReader /* readerp ATS_UNUSED */, int64_t nbytes)
+TSIOBufferReaderConsume(TSIOBufferReader /* readerp ATS_UNUSED */, int64_t nbytes) noexcept
 {
   consumed     += nbytes;
   reader_avail -= nbytes;
 }
 
 int64_t
-TSIOBufferReaderAvail(TSIOBufferReader /* readerp ATS_UNUSED */)
+TSIOBufferReaderAvail(TSIOBufferReader /* readerp ATS_UNUSED */) noexcept
 {
   return reader_avail;
 }
diff --git a/src/api/InkAPI.cc b/src/api/InkAPI.cc
index 04fd974ef6..794cd0aad2 100644
--- a/src/api/InkAPI.cc
+++ b/src/api/InkAPI.cc
@@ -37,6 +37,7 @@
 #include "iocore/net/NetHandler.h"
 #include "iocore/net/UDPNet.h"
 #include "tscore/ink_config.h"
+#include "tscore/ink_error.h"
 #include "tscore/ink_platform.h"
 #include "tscore/ink_base64.h"
 #include "tscore/Encoding.h"
@@ -255,13 +256,15 @@ TSWarning(const char *fmt, ...)
 }
 
 void
-TSError(const char *fmt, ...)
-{
+TSError(const char *fmt, ...) noexcept
+try {
   va_list args;
 
   va_start(args, fmt);
   ErrorV(fmt, args);
   va_end(args);
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 void
@@ -840,8 +843,8 @@ TSfgets(TSFile filep, char *buf, size_t length)
 ////////////////////////////////////////////////////////////////////
 
 TSReturnCode
-TSHandleMLocRelease(TSMBuffer bufp, TSMLoc parent, TSMLoc mloc)
-{
+TSHandleMLocRelease(TSMBuffer bufp, TSMLoc parent, TSMLoc mloc) noexcept
+try {
   MIMEFieldSDKHandle *field_handle;
   HdrHeapObjImpl     *obj = reinterpret_cast<HdrHeapObjImpl *>(mloc);
 
@@ -870,6 +873,8 @@ TSHandleMLocRelease(TSMBuffer bufp, TSMLoc parent, TSMLoc mloc)
     ink_release_assert(!"invalid mloc");
     return TS_ERROR;
   }
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -894,8 +899,8 @@ TSMBufferCreate()
 }
 
 TSReturnCode
-TSMBufferDestroy(TSMBuffer bufp)
-{
+TSMBufferDestroy(TSMBuffer bufp) noexcept
+try {
   // Allow to modify the buffer only
   // if bufp is modifiable. If bufp is not modifiable return
   // TS_ERROR. If allowed, return TS_SUCCESS. Changed the
@@ -909,6 +914,8 @@ TSMBufferDestroy(TSMBuffer bufp)
   sdk_heap->m_heap->destroy();
   delete sdk_heap;
   return TS_SUCCESS;
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1476,8 +1483,8 @@ TSMimeHdrCreate(TSMBuffer bufp, TSMLoc *locp)
 }
 
 TSReturnCode
-TSMimeHdrDestroy(TSMBuffer bufp, TSMLoc obj)
-{
+TSMimeHdrDestroy(TSMBuffer bufp, TSMLoc obj) noexcept
+try {
   // Allow to modify the buffer only
   // if bufp is modifiable. If bufp is not modifiable return
   // TS_ERROR. If allowed, return TS_SUCCESS. Changed the
@@ -1493,6 +1500,8 @@ TSMimeHdrDestroy(TSMBuffer bufp, TSMLoc obj)
 
   mime_hdr_destroy((reinterpret_cast<HdrHeapSDKHandle *>(bufp))->m_heap, mh);
   return TS_SUCCESS;
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 TSReturnCode
@@ -2555,11 +2564,13 @@ TSHttpParserClear(TSHttpParser parser)
 }
 
 void
-TSHttpParserDestroy(TSHttpParser parser)
-{
+TSHttpParserDestroy(TSHttpParser parser) noexcept
+try {
   sdk_assert(sdk_sanity_check_http_parser(parser) == TS_SUCCESS);
   http_parser_clear(reinterpret_cast<HTTPParser *>(parser));
   ats_free(parser);
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 /***********/
@@ -2578,8 +2589,8 @@ TSHttpHdrCreate(TSMBuffer bufp)
 }
 
 void
-TSHttpHdrDestroy(TSMBuffer bufp, TSMLoc obj)
-{
+TSHttpHdrDestroy(TSMBuffer bufp, TSMLoc obj) noexcept
+try {
   sdk_assert(sdk_sanity_check_mbuffer(bufp) == TS_SUCCESS);
   sdk_assert(sdk_sanity_check_http_hdr_handle(obj) == TS_SUCCESS);
 
@@ -2587,6 +2598,8 @@ TSHttpHdrDestroy(TSMBuffer bufp, TSMLoc obj)
   //   so do nothing!
 
   // HDR FIX ME - Did this free the MBuffer in Pete's old system
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 TSReturnCode
@@ -3147,8 +3160,8 @@ TSCacheKeyPinnedSet(TSCacheKey key, time_t pin_in_cache)
 }
 
 TSReturnCode
-TSCacheKeyDestroy(TSCacheKey key)
-{
+TSCacheKeyDestroy(TSCacheKey key) noexcept
+try {
   sdk_assert(sdk_sanity_check_cachekey(key) == TS_SUCCESS);
 
   if ((reinterpret_cast<CacheInfo *>(key))->magic != CACHE_INFO_MAGIC_ALIVE) {
@@ -3161,6 +3174,8 @@ TSCacheKeyDestroy(TSCacheKey key)
   i->magic = CACHE_INFO_MAGIC_DEAD;
   delete i;
   return TS_SUCCESS;
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 TSCacheHttpInfo
@@ -3832,8 +3847,8 @@ TSContCreate(TSEventFunc funcp, TSMutex mutexp)
 }
 
 void
-TSContDestroy(TSCont contp)
-{
+TSContDestroy(TSCont contp) noexcept
+try {
   sdk_assert(sdk_sanity_check_iocore_structure(contp) == TS_SUCCESS);
 
   INKContInternal *i = reinterpret_cast<INKContInternal *>(contp);
@@ -3843,26 +3858,32 @@ TSContDestroy(TSCont contp)
   }
 
   i->destroy();
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 void
-TSContDataSet(TSCont contp, void *data)
-{
+TSContDataSet(TSCont contp, void *data) noexcept
+try {
   sdk_assert(sdk_sanity_check_iocore_structure(contp) == TS_SUCCESS);
 
   INKContInternal *i = reinterpret_cast<INKContInternal *>(contp);
 
   i->mdata = data;
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 void *
-TSContDataGet(TSCont contp)
-{
+TSContDataGet(TSCont contp) noexcept
+try {
   sdk_assert(sdk_sanity_check_iocore_structure(contp) == TS_SUCCESS);
 
   INKContInternal *i = reinterpret_cast<INKContInternal *>(contp);
 
   return i->mdata;
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 TSAction
@@ -6260,8 +6281,8 @@ TSHttpConnectTransparent(sockaddr const *client_addr, sockaddr const *server_add
 
 /* Actions */
 void
-TSActionCancel(TSAction actionp)
-{
+TSActionCancel(TSAction actionp) noexcept
+try {
   Action          *thisaction;
   INKContInternal *i;
 
@@ -6284,6 +6305,8 @@ TSActionCancel(TSAction actionp)
   }
 
   thisaction->cancel();
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 // Currently no error handling necessary, actionp can be anything.
@@ -6441,26 +6464,30 @@ TSVConnWrite(TSVConn connp, TSCont contp, TSIOBufferReader readerp, int64_t nbyt
 }
 
 void
-TSVConnClose(TSVConn connp)
-{
+TSVConnClose(TSVConn connp) noexcept
+try {
   sdk_assert(sdk_sanity_check_iocore_structure(connp) == TS_SUCCESS);
 
   VConnection *vc = reinterpret_cast<VConnection *>(connp);
   vc->do_io_close();
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 void
-TSVConnAbort(TSVConn connp, int error)
-{
+TSVConnAbort(TSVConn connp, int error) noexcept
+try {
   sdk_assert(sdk_sanity_check_iocore_structure(connp) == TS_SUCCESS);
 
   VConnection *vc = reinterpret_cast<VConnection *>(connp);
   vc->do_io_close(error);
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 void
-TSVConnShutdown(TSVConn connp, int read, int write)
-{
+TSVConnShutdown(TSVConn connp, int read, int write) noexcept
+try {
   sdk_assert(sdk_sanity_check_iocore_structure(connp) == TS_SUCCESS);
 
   VConnection *vc = reinterpret_cast<VConnection *>(connp);
@@ -6472,6 +6499,8 @@ TSVConnShutdown(TSVConn connp, int read, int write)
   } else if (write) {
     vc->do_io_shutdown(IO_SHUTDOWN_WRITE);
   }
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 int64_t
@@ -6981,16 +7010,18 @@ TSTextLogObjectWrite(TSTextLogObject the_object, const char *format, ...)
 }
 
 void
-TSTextLogObjectFlush(TSTextLogObject the_object)
-{
+TSTextLogObjectFlush(TSTextLogObject the_object) noexcept
+try {
   sdk_assert(sdk_sanity_check_iocore_structure(the_object) == TS_SUCCESS);
 
   (reinterpret_cast<TextLogObject *>(the_object))->force_new_buffer();
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 TSReturnCode
-TSTextLogObjectDestroy(TSTextLogObject the_object)
-{
+TSTextLogObjectDestroy(TSTextLogObject the_object) noexcept
+try {
   sdk_assert(sdk_sanity_check_iocore_structure(the_object) == TS_SUCCESS);
 
   if (Log::config->log_object_manager.unmanage_api_object(reinterpret_cast<TextLogObject *>(the_object))) {
@@ -6998,6 +7029,8 @@ TSTextLogObjectDestroy(TSTextLogObject the_object)
   }
 
   return TS_ERROR;
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 void
@@ -7309,11 +7342,13 @@ TSFetchLaunch(TSFetchSM fetch_sm)
 }
 
 void
-TSFetchDestroy(TSFetchSM fetch_sm)
-{
+TSFetchDestroy(TSFetchSM fetch_sm) noexcept
+try {
   sdk_assert(sdk_sanity_check_fetch_sm(fetch_sm) == TS_SUCCESS);
 
   (reinterpret_cast<FetchSM *>(fetch_sm))->ext_destroy();
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 void
@@ -8668,9 +8703,11 @@ TSSslServerContextCreate(TSSslX509 cert, const char *certname, const char *rsp_f
 }
 
 void
-TSSslContextDestroy(TSSslContext ctx)
-{
+TSSslContextDestroy(TSSslContext ctx) noexcept
+try {
   SSLReleaseContext(reinterpret_cast<SSL_CTX *>(ctx));
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 TSReturnCode
diff --git a/src/api/InkIOCoreAPI.cc b/src/api/InkIOCoreAPI.cc
index f5f6455fbe..b1a06a5dcf 100644
--- a/src/api/InkIOCoreAPI.cc
+++ b/src/api/InkIOCoreAPI.cc
@@ -28,6 +28,7 @@
  */
 
 #include "tscore/ink_platform.h"
+#include "tscore/ink_error.h"
 #include "ts/ts.h"
 #include "ts/InkAPIPrivateIOCore.h"
 #include "../iocore/net/P_UnixUDPConnection.h"
@@ -160,8 +161,8 @@ TSThreadCreate(TSThreadFunc func, void *data)
 // needs to delete the thread, it must first wait for the thread to
 // complete.
 void
-TSThreadWait(TSThread thread)
-{
+TSThreadWait(TSThread thread) noexcept
+try {
   sdk_assert(sdk_sanity_check_iocore_structure(thread) == TS_SUCCESS);
   INKThreadInternal *ithread = reinterpret_cast<INKThreadInternal *>(thread);
 
@@ -172,6 +173,8 @@ TSThreadWait(TSThread thread)
   }
 
   ink_mutex_release(&ithread->completion.lock);
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 TSThread
@@ -193,8 +196,8 @@ TSThreadInit()
 }
 
 void
-TSThreadDestroy(TSThread thread)
-{
+TSThreadDestroy(TSThread thread) noexcept
+try {
   sdk_assert(sdk_sanity_check_iocore_structure(thread) == TS_SUCCESS);
 
   INKThreadInternal *ithread = reinterpret_cast<INKThreadInternal *>(thread);
@@ -210,6 +213,8 @@ TSThreadDestroy(TSThread thread)
   }
 
   delete ithread;
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 TSThread
@@ -246,8 +251,8 @@ TSMutexCreate()
 }
 
 void
-TSMutexDestroy(TSMutex m)
-{
+TSMutexDestroy(TSMutex m) noexcept
+try {
   sdk_assert(sdk_sanity_check_mutex(m) == TS_SUCCESS);
   ProxyMutex *mutexp = reinterpret_cast<ProxyMutex *>(m);
 
@@ -255,6 +260,8 @@ TSMutexDestroy(TSMutex m)
     ink_release_assert(mutexp->refcount() == 0);
     mutexp->free();
   }
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 /* The following two APIs are for Into work, actually, APIs of Mutex
@@ -288,27 +295,33 @@ TSMutexCheck(TSMutex mutex)
 }
 
 void
-TSMutexLock(TSMutex mutexp)
-{
+TSMutexLock(TSMutex mutexp) noexcept
+try {
   sdk_assert(sdk_sanity_check_mutex(mutexp) == TS_SUCCESS);
   ProxyMutex *proxy_mutex = reinterpret_cast<ProxyMutex *>(mutexp);
   MUTEX_TAKE_LOCK(proxy_mutex, this_ethread());
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 TSReturnCode
-TSMutexLockTry(TSMutex mutexp)
-{
+TSMutexLockTry(TSMutex mutexp) noexcept
+try {
   sdk_assert(sdk_sanity_check_mutex(mutexp) == TS_SUCCESS);
   ProxyMutex *proxy_mutex = reinterpret_cast<ProxyMutex *>(mutexp);
   return (MUTEX_TAKE_TRY_LOCK(proxy_mutex, this_ethread()) ? TS_SUCCESS : TS_ERROR);
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 void
-TSMutexUnlock(TSMutex mutexp)
-{
+TSMutexUnlock(TSMutex mutexp) noexcept
+try {
   sdk_assert(sdk_sanity_check_mutex(mutexp) == TS_SUCCESS);
   ProxyMutex *proxy_mutex(reinterpret_cast<ProxyMutex *>(mutexp));
   MUTEX_UNTAKE_LOCK(proxy_mutex, this_ethread());
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 /* VIOs */
@@ -447,10 +460,12 @@ TSIOBufferSizedCreate(TSIOBufferSizeIndex index)
 }
 
 void
-TSIOBufferDestroy(TSIOBuffer bufp)
-{
+TSIOBufferDestroy(TSIOBuffer bufp) noexcept
+try {
   sdk_assert(sdk_sanity_check_iocore_structure(bufp) == TS_SUCCESS);
   free_MIOBuffer((MIOBuffer *)bufp);
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 TSIOBufferBlock
@@ -657,12 +672,14 @@ TSIOBufferReaderClone(TSIOBufferReader readerp)
 }
 
 void
-TSIOBufferReaderFree(TSIOBufferReader readerp)
-{
+TSIOBufferReaderFree(TSIOBufferReader readerp) noexcept
+try {
   sdk_assert(sdk_sanity_check_iocore_structure(readerp) == TS_SUCCESS);
 
   IOBufferReader *r = (IOBufferReader *)readerp;
   r->mbuf->dealloc_reader(r);
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 TSIOBufferBlock
@@ -680,20 +697,24 @@ TSIOBufferReaderStart(TSIOBufferReader readerp)
 }
 
 void
-TSIOBufferReaderConsume(TSIOBufferReader readerp, int64_t nbytes)
-{
+TSIOBufferReaderConsume(TSIOBufferReader readerp, int64_t nbytes) noexcept
+try {
   sdk_assert(sdk_sanity_check_iocore_structure(readerp) == TS_SUCCESS);
   sdk_assert(nbytes >= 0);
 
   IOBufferReader *r = (IOBufferReader *)readerp;
   r->consume(nbytes);
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
 
 int64_t
-TSIOBufferReaderAvail(TSIOBufferReader readerp)
-{
+TSIOBufferReaderAvail(TSIOBufferReader readerp) noexcept
+try {
   sdk_assert(sdk_sanity_check_iocore_structure(readerp) == TS_SUCCESS);
 
   IOBufferReader *r = (IOBufferReader *)readerp;
   return r->read_avail();
+} catch (...) {
+  ink_abort("exception escaped %s", __func__);
 }
diff --git a/src/cripts/unit_tests/stub.cc b/src/cripts/unit_tests/stub.cc
index 65680db4a1..9214b514b1 100644
--- a/src/cripts/unit_tests/stub.cc
+++ b/src/cripts/unit_tests/stub.cc
@@ -28,7 +28,7 @@ TSWarning(const char * /* fmt */, ...)
 }
 
 void
-TSError(const char * /* fmt */, ...)
+TSError(const char * /* fmt */, ...) noexcept
 {
 }
 
@@ -39,12 +39,12 @@ TSContCreate(TSEventFunc, TSMutex)
 }
 
 void
-TSContDataSet(TSCont, void *)
+TSContDataSet(TSCont, void *) noexcept
 {
 }
 
 void *
-TSContDataGet(TSCont)
+TSContDataGet(TSCont) noexcept
 {
   return nullptr;
 }
@@ -62,12 +62,12 @@ TSContScheduleEveryOnPool(TSCont, TSHRTime, TSThreadPool)
 }
 
 void
-TSActionCancel(TSAction)
+TSActionCancel(TSAction) noexcept
 {
 }
 
 void
-TSContDestroy(TSCont)
+TSContDestroy(TSCont) noexcept
 {
 }
 
diff --git a/src/iocore/cache/unit_tests/stub.cc b/src/iocore/cache/unit_tests/stub.cc
index 177f20be1e..50c8239b05 100644
--- a/src/iocore/cache/unit_tests/stub.cc
+++ b/src/iocore/cache/unit_tests/stub.cc
@@ -51,7 +51,7 @@ TSIOBufferBlockReadStart(TSIOBufferBlock /* blockp ATS_UNUSED */, TSIOBufferRead
 }
 
 void
-TSIOBufferReaderConsume(TSIOBufferReader /* readerp ATS_UNUSED */, int64_t /* nbytes ATS_UNUSED */)
+TSIOBufferReaderConsume(TSIOBufferReader /* readerp ATS_UNUSED */, int64_t /* nbytes ATS_UNUSED */) noexcept
 {
 }
 
diff --git a/src/tsutil/Assert.cc b/src/tsutil/Assert.cc
index e94e29956d..20e45b44f8 100644
--- a/src/tsutil/Assert.cc
+++ b/src/tsutil/Assert.cc
@@ -28,8 +28,8 @@
 #include <syslog.h>
 
 void
-ts::do_abort(const SourceLocation &loc, const char *expr, const char *message)
-{
+ts::do_abort(const SourceLocation &loc, const char *expr, const char *message) noexcept
+try {
   swoc::LocalBufferWriter<1024> w;
 
   w.print("Fatal: <{}> {}", loc, expr);
@@ -40,5 +40,10 @@ ts::do_abort(const SourceLocation &loc, const char *expr, const char *message)
   fprintf(stderr, "%s\n", w.data());
   syslog(LOG_CRIT, "%s", w.data());
 
+  abort();
+} catch (...) {
+  // Formatting the message must not stop the abort, and an exception must not
+  // escape into callers' noexcept contexts (e.g. destructors).
+  fprintf(stderr, "Fatal: <%s> (abort message formatting threw)\n", expr);
   abort();
 }