Skip to content

Release paths silently swallow unexpected exceptions via catch (...) plus ASSERT(0)

Summary

Several live release paths still use catch (...) { ASSERT(0); } or an equivalent shape that turns unexpected exceptions into effectively silent failure in non-debug builds.

This is broader than the focused ArchiveRecovery item in BUG-002: the same pattern appears in multiple subsystems that process external input, files, or network-derived state.

Representative Live Sites

  • srchybrid/ArchiveRecovery.cpp
  • srchybrid/Collection.cpp
  • srchybrid/WebServer.cpp
  • srchybrid/ServerSocket.cpp

These are representative anchors, not an exhaustive list.

Why This Matters

In debug builds, ASSERT(0) makes the failure visible. In release builds, the assert disappears and the catch (...) often leaves only a quiet early-return or partial fallback path.

That makes production diagnosis harder:

  • users get no actionable error signal
  • logs miss the root event
  • corrupted or partial state can be misinterpreted as a normal functional miss

Intended Fix Direction

Do not treat this as a blanket “log everything and continue” sweep.

Preferred remediation pattern:

  1. preserve the current safe-fail behavior where it is already bounded
  2. add explicit logging where practical and meaningful
  3. convert a few sites to typed exception handling where the thrown failure shape is already known
  4. avoid rethrow/crash behavior unless the local code path is truly unsafe to continue

Current Mainline Outcome

The first bounded diagnostics slice landed on main in commit 9992cb1 (BUG-034 BUG-035: add bounded runtime failure logs), and monitored shared refresh failure handling was narrowed in commit 60b3b44.

The collection-import slice adds typed logging for unreadable binary collection entries and keeps unexpected import failures explicit while preserving the existing tolerant skip behavior for malformed per-file entries.

The collection-file import slice extends that work inside each serialized file entry: hostile tag counts are rejected before parsing, malformed individual tags are logged instead of swallowed silently, and hashless entries are rejected with a typed reason so the outer collection loader can skip them explicitly.

The secure-ident slice narrows ClientCredits crypto/signature failures by making buffer and key-length rejection explicit and keeping unexpected signature exceptions on the existing zero-length failure result.

The server TCP packet slice makes the existing recover-or-disconnect policy for server packet processing explicit through ServerSocketSeams: search-result and found-source parse failures remain recoverable, compressed-packet unpack failures remain consumed input, and unexpected packet-processing exceptions now use safe fallback metadata for failure logs.

The legacy WebServer search slice keeps unexpected search-start exceptions on the existing generic error response through WebServerLegacySeams, and makes the historical gzip failure fallback to an uncompressed response explicit.

The 2026-05-01 release-readiness scan found no rollback-level regression in the recent hardening slices, but it did identify srchybrid/ClientUDPSocket.cpp as the next best high-signal target: unknown release exceptions while processing external UDP packets are still converted to "Unknown exception" and logged only when verbose logging is enabled.

The client UDP slice landed on main in commit 6b76687 and adds a ClientUDPSocketSeams policy so unexpected packet-processing exceptions force a release log while ordinary malformed packet diagnostics remain verbose-gated. Native coverage for that policy landed in emulebb-build-tests commit 6af34cc; the supported Debug x64 test lane passed after the change.

The server UDP slice landed on main in commit 16f50ba and applies the same policy to CUDPSocket::ProcessPacketError: expected server UDP packet parse failures remain verbose-gated, while unexpected release exceptions force a diagnostic log. Native coverage landed in emulebb-build-tests commit 80bfa14; the supported Debug x64 test lane passed after the change.

The async socket helper-init slice landed on main in commit cf4bbb1 and makes CAsyncSocketEx::InitAsyncSocketExInstance() helper-window allocation or construction exceptions release-visible through an explicit DebugLogError while preserving the existing cleanup and false return. Native policy coverage landed in emulebb-build-tests commit ad49ff8; the supported Debug x64 build-app and test lanes passed after the change.

The Windows toast notification slice landed on main in commit c6e3d9c and keeps toast initialization/display failure behavior fail-soft while making typed C++/WinRT hresult_error failures and unexpected exceptions visible in the debug/error log. This covers both CreateToastNotifier initialization and per-toast Show failures, including payload cleanup after failed display. Validation passed with workspace validate, Debug x64 main app build, and Release x64 main app build.

This item is therefore In Progress, not Open. It is not Done: the 2026-05-01 scan still finds broad release-silent exception handling in current main, including 123 catch (...) matches across app source. Future slices should stay targeted and high-signal rather than attempting a mechanical codebase-wide rewrite.

Relationship to Existing Items

  • BUG-002 remains the focused ArchiveRecovery representative item
  • BUG-013 remains the separate ArchiveRecovery OOM/null-deref item

This item exists to track the broader release-silent exception-swallowing pattern across subsystems, not to replace those narrower archive items.