bryancall opened a new pull request, #13590:
URL: https://github.com/apache/trafficserver/pull/13590

   Exceptions have never been a supported error channel across the plugin API: 
API functions report failure through return values, and no header or document 
has ever promised that a TS API call throws anything a plugin could catch. That 
contract was never written down, though, so any exception escaping from the 
core into plugin code is both undiagnosable and invisible to static analysis.
   
   It matters most in destructors. Plugin destructors routinely call the API 
cleanup functions, destructors are implicitly `noexcept`, and so an exception 
escaping one of those calls terminates the process with no attribution at all.
   
   ### What this does
   
   - Annotates 28 API functions `noexcept` in `ts.h` — the cleanup/teardown 
family that destructors call (`TSContDestroy`, `TSHandleMLocRelease`, 
`TSIOBuffer*`/`TSMBufferDestroy`, `TSHttpHdrDestroy`, `TSMimeHdrDestroy`, 
`TSVConn{Close,Abort,Shutdown}`, `TSActionCancel`, `TSCacheKeyDestroy`, 
`TSSslContextDestroy`, `TSFetchDestroy`, `TSTextLogObject*`, the `TSMutex*` 
family, `TSThread{Wait,Destroy}`, `TSContData{Get,Set}`, and `TSError`).
   - Converts each definition to a function-try-block whose handler calls 
`ink_abort("exception escaped %s", __func__)`. An exception that would 
previously have escaped now produces a named, attributable abort instead of a 
bare `std::terminate` inside a plugin destructor.
   - Annotates `ts::do_abort` `[[noreturn]] noexcept` and contains formatting 
failures inside it, and does the same for `ts::shared_mutex::_call_fatal`. Both 
build their message with `swoc::bwprint`/`Strerror`, which allocate, so the 
abort path could itself throw `bad_alloc` before reaching the abort — from 
inside `~write_guard`/`~read_guard`.
   - Updates the matching prototypes in the developer guide (22 pages) and 
states the no-exceptions contract in the plugin getting-started chapter.
   
   ### Overhead
   
   None on the happy path, as expected for table-driven exception handling. 
Comparing generated code for a representative wrapped function against the same 
function unwrapped, the instruction sequences are identical except that the 
final call can no longer be a tail call. Measured on `InkAPI.cc` built before 
and after with identical flags: `__text` grew 896 bytes (+0.66%, about 45 bytes 
per wrapped function) and `__gcc_except_tab` grew 500 bytes of read-only data 
that is never touched unless an exception unwinds.
   
   In the other direction this is a small optimization enabler: callers that 
can see `noexcept` no longer need their own landing pads around these calls, so 
plugin cleanup code should get marginally smaller.
   
   ### Coverity
   
   `UNCAUGHT_EXCEPT` is the single largest class of outstanding defects on the 
[Coverity Scan 
project](https://scan.coverity.com/projects/apache-traffic-server): 203 of 538 
in the High Impact Outstanding view (build master-20260826).
   
   Parsing the body of every flagged destructor, 83 findings are directly 
attributable to this change — 80 destructors whose only calls are functions 
this PR makes `noexcept`, plus 3 `TsSharedMutex` guard destructors covered by 
the `_call_fatal` fix. By area: 61 in plugins, 13 in `tscpp/api`, 5 in core, 2 
in examples, 2 in test code. Representative CIDs: 1528663, 1528712, 1660590, 
1660588, 1533104, 1528778.
   
   The other 120 need separate root causes (the `main()` entry points in the 
CLI tools, and destructors whose throw path is a member subobject rather than 
an API call); those are follow-up changes, not this one.
   
   ### Notes for reviewers
   
   - **Behavior change:** a plugin that wrapped a TS API call in a `catch` 
expecting to catch a core-internal exception would now see an abort. Exceptions 
were never a supported error channel here, so this standardizes existing 
practice rather than removing a documented one — but it is a real change and 
worth a release note.
   - **Source compatibility:** since C++17 `noexcept` is part of the function 
type, so any translation unit that includes `ts.h` *and* separately declares 
one of these functions without `noexcept` becomes ill-formed. Seven in-tree 
test stubs that redefine API functions needed the annotation added; out-of-tree 
plugins doing the same will need the same one-word change. The stub edits are 
mechanical and have to land in the same commit or the build breaks, which is 
why they are here rather than split out.
   - **Selection rule:** the set is "the cleanup/teardown entry points a 
destructor can reasonably call," derived by parsing what the flagged 
destructors actually call, then extended to the obvious siblings 
(`TSMutexDestroy`, `TSMutexLockTry`, `TSMimeHdrDestroy`, `TSSslContextDestroy`) 
so the boundary is not an artifact of a scanner hit list. Widening it to the 
whole API surface is a reasonable follow-up if reviewers prefer that; it did 
not seem like the right first step.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to