SDK1 host disposal omits terminal server Dispose and retains stopped server graph #807

Closed
opened 2026-11-10 16:48:01 -05:00 by dohertj2 · 1 comment
Owner

Discovered while investigating #799 against unchanged original83ed880e publications. The SDK1 host DisposeAsync calls ApplicationInstance.StopAsync but never calls terminal server.Dispose. Exact1.5.378.182 source distinguishes these operations: Stop disposes current server-internal data; ServerBase.Dispose additionally disposes its RequestQueue, while StandardServer.Dispose unregisters certificate-update callbacks.

A bounded two-phase control verifies closed session/point objects collect while the same host lives, but after normal host stop five server graph witnesses remain through five fixed GC rounds (server, node manager, historian backend, validator and cached store). A separate counterfactual preserves that ordinary failure, then invokes public ServerBase.Dispose exactly once at an isolated helper boundary: all five witnesses collect in the first subsequent GC round, active timers7→2. Ordinary test exit1 stays failed. This supports the missing terminal-disposal ownership explanation, not an actual GC-root trace identifying a particular timer. Actual PKI FDs remain0.

Repair the supported SDK1 application host ownership separately on master: single-owner, shared-completion Dispose; detach authentication handler, stop the application and guarantee terminal server.Dispose; reject Start after disposal begins. Cover actual booted red/green, repeated/concurrent Dispose with barriers, failed startup and throwing Stop, plus existing security/PKI reuse tests. Astra approved this design; actual source/results approval is required before pushing master.

Frozen83 baseline DLLs/oracles remain unchanged and are not relabelled. SDK2 already uses ApplicationInstance.DisposeAsync, which stops and terminally disposes its server; no SDK2 production workaround or resource-budget change is part of this repair. #799/G4 remain open pending their distinct native/performance/soak evidence.

Discovered while investigating #799 against unchanged original83ed880e publications. The SDK1 host DisposeAsync calls ApplicationInstance.StopAsync but never calls terminal server.Dispose. Exact1.5.378.182 source distinguishes these operations: Stop disposes current server-internal data; ServerBase.Dispose additionally disposes its RequestQueue, while StandardServer.Dispose unregisters certificate-update callbacks. A bounded two-phase control verifies closed session/point objects collect while the same host lives, but after normal host stop five server graph witnesses remain through five fixed GC rounds (server, node manager, historian backend, validator and cached store). A separate counterfactual preserves that ordinary failure, then invokes public ServerBase.Dispose exactly once at an isolated helper boundary: all five witnesses collect in the first subsequent GC round, active timers7→2. Ordinary test exit1 stays failed. This supports the missing terminal-disposal ownership explanation, not an actual GC-root trace identifying a particular timer. Actual PKI FDs remain0. Repair the supported SDK1 application host ownership separately on master: single-owner, shared-completion Dispose; detach authentication handler, stop the application and guarantee terminal server.Dispose; reject Start after disposal begins. Cover actual booted red/green, repeated/concurrent Dispose with barriers, failed startup and throwing Stop, plus existing security/PKI reuse tests. Astra approved this design; actual source/results approval is required before pushing master. Frozen83 baseline DLLs/oracles remain unchanged and are not relabelled. SDK2 already uses ApplicationInstance.DisposeAsync, which stops and terminally disposes its server; no SDK2 production workaround or resource-budget change is part of this repair. #799/G4 remain open pending their distinct native/performance/soak evidence.
dohertj2 added the type:bugpriority:p2 labels 2026-11-10 16:48:01 -05:00
Author
Owner

Fixed and pushed independently to SDK1 master at efb9197a (implementation10edc44f). The host now elects one terminal cleanup owner, detaches the callback, stops the application and guarantees public server.Dispose; concurrent/repeated disposers await shared completion, and disposed hosts reject new startup. This protects owner publication/capture; it does not claim full concurrent async Start/Dispose support.

All five meaningful regression tests first failed against byte-identical old master production: missing terminal Dispose on normal/throwing-Stop/partial-start paths; four Stop calls from concurrent disposers; startup accepted after disposal. All five pass after the fix. Owning suite: 1032 passed,0 failed,1 existing skip, including host security and same-PKI two-boot checks. Whole solution Release build:0 warnings/errors. Astra independently verified actual source, raw TRX, hashes, RED attribution and final package.

Versioned evidence. Original83ed880e publications/oracles are unchanged; this repair is not a replacement performance denominator or #799/G4 pass. SDK2 remains separate on draft PR#802 and is not merged/deployed. Closing this specific SDK1 ownership repair.

Fixed and pushed independently to SDK1 master at **efb9197a** (implementation10edc44f). The host now elects one terminal cleanup owner, detaches the callback, stops the application and guarantees public server.Dispose; concurrent/repeated disposers await shared completion, and disposed hosts reject new startup. This protects owner publication/capture; it does not claim full concurrent async Start/Dispose support. All five meaningful regression tests first failed against byte-identical old master production: missing terminal Dispose on normal/throwing-Stop/partial-start paths; four Stop calls from concurrent disposers; startup accepted after disposal. All five pass after the fix. Owning suite: **1032 passed,0 failed,1 existing skip**, including host security and same-PKI two-boot checks. Whole solution Release build:0 warnings/errors. Astra independently verified actual source, raw TRX, hashes, RED attribution and final package. [Versioned evidence](https://gitea.dohertylan.com/dohertj2/lmxopcua/src/commit/efb9197a/docs/plans/evidence/2026-11-10-sdk1-terminal-disposal.json). Original83ed880e publications/oracles are unchanged; this repair is not a replacement performance denominator or #799/G4 pass. SDK2 remains separate on draft PR#802 and is not merged/deployed. Closing this specific SDK1 ownership repair.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#807