fix(server): stop WriteNodeIdUnknown infinite recursion (Server-001)

WriteNodeIdUnknown called itself unconditionally as its first statement
— unbounded recursion with no base case → StackOverflowException, an
uncatchable process crash reachable by any client issuing a HistoryRead
on an unresolvable NodeId (remote DoS).

Replace the self-call with the result-slot assignment, mirroring
WriteUnsupported / WriteInternalError. The helper is now internal so the
regression test can pin the StatusCode without a server fixture.

Resolves code-review finding Server-001 (Critical).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-22 05:53:44 -04:00
parent 8568f5cd85
commit 571066130b
3 changed files with 41 additions and 5 deletions

View File

@@ -1788,9 +1788,10 @@ public sealed class DriverNodeManager : CustomNodeManager2, IAddressSpaceBuilder
errors[i] = StatusCodes.BadUserAccessDenied;
}
private static void WriteNodeIdUnknown(IList<OpcHistoryReadResult> results, IList<ServiceResult> errors, int i)
// Internal so the test suite can pin the StatusCode without booting a server fixture.
internal static void WriteNodeIdUnknown(IList<OpcHistoryReadResult> results, IList<ServiceResult> errors, int i)
{
WriteNodeIdUnknown(results, errors, i);
results[i] = new OpcHistoryReadResult { StatusCode = StatusCodes.BadNodeIdUnknown };
errors[i] = StatusCodes.BadNodeIdUnknown;
}