Skip to content

Historical control-flow still uses bare ASSERT(0) without recovery or logging

Summary

There is still a broad class of historical control-flow debt where ASSERT(0) is used as a placeholder for “should never happen” without a real recovery, error-reporting, or logging path behind it.

This is distinct from BUG-034, which tracks release-silent catch (...) patterns. BUG-035 tracks direct control-flow paths that fall into bare assertions without exception handling at all.

Representative Live Sites

  • srchybrid/TreePropSheet.cpp
  • srchybrid/TransferWnd.cpp
  • srchybrid/SHAHashSet.cpp

These are representative anchors, not an exhaustive list.

Why This Matters

In debug builds, these sites surface as assert dialogs. In release builds, the assert usually disappears, leaving one of these outcomes:

  • silent no-op behavior
  • implicit fallthrough into whatever follows
  • partially-updated UI or state with no operator-visible explanation

That makes the code harder to reason about and makes production failures harder to diagnose than they should be.

Intended Fix Direction

Do not replace every ASSERT(0) mechanically.

Preferred remediation pattern:

  1. keep assertion coverage where it still documents impossible invariants in debug builds
  2. add explicit recovery or early-return behavior for live runtime paths
  3. add logging where practical and useful
  4. convert a few high-value sites into explicit error handling helpers where a repeated pattern exists

Current Mainline Outcome

The first bounded diagnostics slice landed on main in commit 9992cb1 (BUG-034 BUG-035: add bounded runtime failure logs). Commit a962351 also hardened selected Unicode INI and UTF-8 decoding paths that previously had weak release-mode behavior.

The collection-import slice also narrows one ownership/recovery path by making rejected imported collection entries explicitly importer-owned until accepted, so duplicate or invalid entries are disposed without changing the public collection API.

The collection-file import slice also turns missing file hashes and invalid AICH hash metadata into explicit release-mode policy: hashless entries are rejected and logged through the binary-entry skip path, while malformed optional AICH tags are logged and ignored without rejecting the rest of the entry.

The secure-ident slice also moves ClientCredits key/signature failure results behind small seam helpers, preserving the existing failed-ident transitions while avoiding implicit release-mode fallthrough on oversized inputs.

The server TCP packet slice also moves the CServerSocket packet-failure continue/disconnect decision behind a small seam helper. This keeps the debug assertions as invariant markers while making the release-mode behavior explicit and covered by native tests.

The legacy WebServer search slice also moves unsupported file-type clearing, failed-start parameter ownership, generic exception fallback, and gzip fallback policy behind small seam helpers. The user-visible behavior stays compatible, but the release-mode control flow is now explicit and covered by native tests.

The Transfer window slice moves invalid primary/secondary view-state handling behind TransferWndSeams. Bad persisted or runtime view ids now use explicit release-mode fallbacks instead of only hitting debug assertions, and the fallback policy is covered by native tests.

The 2026-05-01 release-readiness scan found no rollback-level regression in the recent control-flow hardening slices. It does keep the client UDP unknown exception path as the next practical release-silent target because that site still combines a release-only catch (...) fallback with a debug-only ASSERT(0) marker and verbose-gated diagnostics.

The client UDP slice landed on main in commit 6b76687 and narrows that specific combined pattern: the debug assertion remains as an invariant marker, but release-mode unexpected packet exceptions now force a diagnostic log through the new ClientUDPSocketSeams policy. Native coverage for the policy landed in emulebb-build-tests commit 6af34cc.

The server UDP slice landed on main in commit 16f50ba and narrows the same release-mode pattern for CUDPSocket::ProcessPacketError: debug assertions remain as invariant markers, while unexpected release exceptions now bypass the verbose-only logging gate. Native coverage for the policy landed in emulebb-build-tests commit 80bfa14.

The async socket helper-init slice landed on main in commit cf4bbb1 and narrows another release-silent initialization failure: helper-window allocation or construction exceptions in CAsyncSocketEx::InitAsyncSocketExInstance() now keep their existing cleanup and failure return, but the release build records a diagnostic log. Native policy coverage landed in emulebb-build-tests commit ad49ff8.

This item is In Progress, not Done: the 2026-05-01 scan still finds 541 ASSERT(0) matches in current app source. Many are legitimate invariant checks, but enough live control-flow sites remain that this should stay as a broad hardening bucket with future targeted slices.

Relationship to Existing Items

  • BUG-034 covers catch (...) plus ASSERT(0) silent exception swallowing
  • BUG-002 remains the focused ArchiveRecovery representative issue

BUG-035 exists to track the broader direct-control-flow ASSERT(0) debt that is not primarily exception-driven.