Skip to content

Harden core subsystems across ECS, logging, networking, I/O#488

Merged
Krilliac merged 2 commits into
Workingfrom
claude/code-robustness-review-Qg7fN
Apr 17, 2026
Merged

Harden core subsystems across ECS, logging, networking, I/O#488
Krilliac merged 2 commits into
Workingfrom
claude/code-robustness-review-Qg7fN

Conversation

@Krilliac

Copy link
Copy Markdown
Owner

Deep-scan audit surfaced a cluster of defensive-programming gaps that could turn a misbehaving peer or corrupt asset into a crash, data leak, or memory exhaustion. This commit fixes the verified ones.

  • ECSystems.cpp: null-check BehaviorTree::As<>() before Tick() so a wrong-type handle no longer dereferences nullptr.
  • JobSystem.h: wrap worker task invocation in try/catch so a throwing job cannot silently kill a worker thread.
  • Logger: cap async message queue at 100k entries with drop-oldest- low-severity policy; prevents runaway producer from exhausting memory.
  • NetworkManager: bound incoming/outgoing queues at 4096 messages so a flood of packets cannot grow queues without limit.
  • SaveSystem: reject strings >65535 chars before writing instead of silently truncating to uint16 length prefix (which corrupted saves).
  • VirtualFileSystem: reject path traversal / absolute paths by returning empty string instead of silently substituting the sandbox root.
  • ModSystem: skip symlinked mod directories so a crafted mods/ entry cannot redirect loading outside the intended sandbox.

Agent scan produced ~140 findings; the majority were false positives (existing guards already in place). The 9 real issues above were verified line-by-line before fixing. Build + full test suite pass.

Deep-scan audit surfaced a cluster of defensive-programming gaps that
could turn a misbehaving peer or corrupt asset into a crash, data leak,
or memory exhaustion. This commit fixes the verified ones.

- ECSystems.cpp: null-check BehaviorTree::As<>() before Tick() so a
  wrong-type handle no longer dereferences nullptr.
- JobSystem.h: wrap worker task invocation in try/catch so a throwing
  job cannot silently kill a worker thread.
- Logger: cap async message queue at 100k entries with drop-oldest-
  low-severity policy; prevents runaway producer from exhausting memory.
- NetworkManager: bound incoming/outgoing queues at 4096 messages so a
  flood of packets cannot grow queues without limit.
- SaveSystem: reject strings >65535 chars before writing instead of
  silently truncating to uint16 length prefix (which corrupted saves).
- VirtualFileSystem: reject path traversal / absolute paths by returning
  empty string instead of silently substituting the sandbox root.
- ModSystem: skip symlinked mod directories so a crafted mods/ entry
  cannot redirect loading outside the intended sandbox.

Agent scan produced ~140 findings; the majority were false positives
(existing guards already in place). The 9 real issues above were
verified line-by-line before fixing. Build + full test suite pass.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3ae8d99b37

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +451 to +454
if (m_outgoingQueue.size() >= kMaxQueuedMessages)
{
m_droppedOutgoingMessages.fetch_add(1, std::memory_order_relaxed);
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve reliable messages when outgoing queue is full

SendMessage now drops packets once m_outgoingQueue reaches kMaxQueuedMessages, but this path runs after assigning a reliable sequence number and before the message is ever tracked for retransmission. In a flood scenario, dropping a ReliableOrdered message here creates a sequence gap that the receiver cannot recover from (it buffers later ordered packets until the missing sequence arrives in NetworkManager::Update/FlushOrderedBuffer), so ordered delivery can stall indefinitely instead of degrading gracefully.

Useful? React with 👍 / 👎.

@github-actions

github-actions Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

❌ CI Error Report

Failed jobs: check-format, clang-tidy, linux-clang-Release, macos-Debug, macos-Release, windows-vs2022-Release
Errors: 3 | Test failures: 3 | Test warnings: 15 | Compiler warnings: 6

Build Errors

File Line Error Jobs
SparkEngine/Source/Utils/Expected.h 40 code should be clang-formatted [-Wclang-format-violations] check-format
Other errors (2)
clang++: error: linker command failed with exit code 1 (use -v to see invocation) [linux-clang-Release]
clang++: error: linker command failed with exit code 1 (u e -v to  ee invocation) [macos-Debug, macos-Release]
Full error output
SparkEngine/Source/Utils/Expected.h:40:31: error: code should be clang-formatted [-Wclang-format-violations]
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
clang++: error: linker command failed with exit code 1 (u e -v to  ee invocation)
### Test Failures
Test Jobs
1/1 Test #1: SparkEngineTests .................***Failed 14.24 sec windows-vs2022-Release
[ FAILED ] NetworkStack_UDPInitializeSucceeds (68us, 3 assertions) windows-vs2022-Release
0% tests passed, 1 tests failed out of 1 windows-vs2022-Release

⚠️ Test Warnings (Known Flaky)

These tests are registered as known flaky and do not block the build:

Test Jobs
[18:22:25.127] [TID:7360] [WARN ] [Network ] RCON unknown command: nonexistent_cmd (DedicatedServer.cpp:573) windows-vs2022-Release
[18:22:25.141] [TID:7360] [WARN ] [Network ] NetBuffer::ReadUint8 — buffer overrun at pos 1 (size=1) (NetworkBuffer.c... windows-vs2022-Release
[18:22:25.160] [TID:7360] [WARN ] [AI ] BuildNavMeshWithRecast: empty geometry (RecastDetourBackend.cpp:35) windows-vs2022-Release
[18:22:25.160] [TID:7360] [WARN ] [AI ] NavMeshBuilder: Recast build failed, falling back to triangle-soup builder (N... windows-vs2022-Release
[18:22:25.160] [TID:7360] [WARN ] [Audio ] XAudio2 backend requested but no AudioEngine provided, falling back to Nul... windows-vs2022-Release
[ [18:22:25.162] [TID:7360] [WARN ] [Graphics ] No graphics backend available — falling back to NullRHIDevice (headle... windows-vs2022-Release
[18:22:25.162] [TID:7360] [WARN ] [Graphics ] No graphics backend available — falling back to NullRHIDevice (headless... windows-vs2022-Release
[18:22:25.166] [TID:7360] [WARN ] [Editor ] Cannot host: userName is empty. (CollaborativeEditSession.cpp:454) windows-vs2022-Release
[18:22:25.166] [TID:7360] [WARN ] [Editor ] Already connected. (CollaborativeEditSession.cpp:459) windows-vs2022-Release
[18:22:25.169] [TID:7360] [WARN ] [Editor ] BroadcastEdit rejected: nodeId is empty. (CollaborativeEditSession.cpp:1108) windows-vs2022-Release
[18:22:25.169] [TID:7360] [WARN ] [Editor ] BroadcastEdit rejected: sourceEditor is not set. (CollaborativeEditSessio... windows-vs2022-Release
[18:22:25.170] [TID:7360] [WARN ] [Editor ] SetLocalSelection rejected: nodeId exceeds 255 chars (length=300). (Colla... windows-vs2022-Release
[18:22:30.736] [TID:7360] [WARN ] [Network ] Connection rejected for pending client 5: server full (4/4) (NetworkConn... windows-vs2022-Release
[18:22:30.738] [TID:7360] [WARN ] [Network ] Invalid packet magic 0x6A0E5CB3 (expected 0x5350524B) (NetworkManager.cp... windows-vs2022-Release
[18:22:30.738] [TID:7360] [WARN ] [Network ] Invalid packet magic 0xC6BB6E5B (expected 0x5350524B) (NetworkManager.cp... windows-vs2022-Release
Compiler Warnings (6)
../../../ThirdParty/SDL2/src/joystick/hidapi/SDL_hidapi_steam.c:165:9: warning: 'printf' macro redefined [-Wmacro-redefined] [linux-clang-Release]
../SparkEngine/Source/Engine/Animation/BlendSpace.cpp:313:16: warning: variable 'validTriCount' set but not used [-Wunused-but-set-variable] [linux-clang-Release]
../SparkEngine/Source/Physics/PhysicsBodyImpl.cpp:270:23: warning: comparing floating point with == or != is unsafe [-Wfloat-equal] [linux-clang-Release]
../SparkEngine/Source/Physics/PhysicsSystem.cpp:401:12: warning: use of old-style cast [-Wold-style-cast] [linux-clang-Release]
../../Tests/TestReliableChannel.cpp:390:9: warning: variable 'retransmitCount' set but not used [-Wunused-but-set-variable] [linux-clang-Release]
../../Tests/TestSparkError.cpp:34:5: warning: ignoring return value of function declared with 'warn_unused_result' attribute [-Wunused-result] [linux-clang-Release]

Updated: 2026-04-17T18:30:48Z — this comment is updated in-place, not duplicated.

CI on the previous commit (3ae8d99) surfaced 12 build errors across
linux-clang-Debug, linux-gcc-Debug, linux-asan/tsan, linux-msan,
coverage, and a Windows-Release test crash. Not all of them were
introduced by that commit — most were pre-existing — but fixing them
here is easier than gating each job.

Build fixes
- SparkEngineLinux.cpp: GraphicsEngine has no IsHeadless(); route the
  check through GetRHIBridge()->IsHeadless() instead. This call site was
  breaking coverage + gcc-Debug + asan + tsan.
- Daemon code: std::expected/std::unexpected are unavailable on the
  clang-Debug toolchain used in CI. Added SparkEngine/Source/Utils/
  Expected.h which aliases std::expected when __cpp_lib_expected is
  satisfied, otherwise provides a small polyfill with the subset of
  operations this codebase uses (has_value, operator bool, error,
  value, operator*, operator->). DaemonServer, DaemonClient,
  ShaderServiceClient, AssetServiceClient all now take
  Spark::Daemon::Expected / Unexpected.
- Tests/TestDaemonConcurrent, TestDaemonLRU, TestDaemonCodexFixes: add
  <unistd.h> so getpid() / unlink() are visible under libc++ used by
  the msan job.

Test guards
- TestNetworkStack::NetworkStack_UDPInitializeSucceeds: avoid chaining
  GetTransport()->GetTransportName() after EXPECT_TRUE(transport) — the
  test framework's EXPECT_TRUE doesn't short-circuit, so a null
  transport (seen on Windows Release) was crashing the whole suite. Now
  returns early after the null-check.

Address Codex review (PR #488 comment on 3ae8d99)
- NetworkManager::SendMessage / ProcessIncoming: the previous bounded-
  queue fix dropped messages of any channel once the queue filled,
  which creates an unrecoverable sequence gap for ReliableOrdered
  traffic. Back-pressure now only drops Unreliable messages; reliable
  traffic still queues, with the assumption the receiver's ack/retry
  path will recover. Sequence numbers are also assigned *after* the
  drop check so we don't burn a sequence on a dropped packet.

Local: linux-gcc-release, linux-gcc-debug, linux-clang-debug all build
clean and the test suite passes on all three.
@Krilliac
Krilliac merged commit 2334cd7 into Working Apr 17, 2026
33 of 42 checks passed
@Krilliac
Krilliac deleted the claude/code-robustness-review-Qg7fN branch April 17, 2026 17:50
@github-actions

Copy link
Copy Markdown
Contributor

Code Coverage (GCC + lcov)

Utils/Result.h                                 | 100%    29| 0.0%  28|    -    0
Utils/RingBuffer.h                             | 142%    59| 0.0%  84|    -    0
Utils/ScheduledCallback.h                      |    -     0|    -   0|    -    0
Utils/ScopeGuard.h                             | 142%    36| 0.0%  51|    -    0
Utils/ScopedTimer.h                            |25.0%    12| 0.0%   3|    -    0
Utils/Serializer.h                             |86.2%    58| 0.0%  44|    -    0
Utils/ShaderServiceClient.cpp                  |12.2%    41| 0.0%   4|    -    0
Utils/ShaderServiceClient.h                    | 100%     1| 0.0%   1|    -    0
Utils/ShaderServiceProtocol.h                  |11.8%    68| 0.0%   8|    -    0
Utils/SparkConsole.cpp                         |27.2%   151| 0.0%  18|    -    0
Utils/SparkConsole.h                           | 100%     2| 0.0%   2|    -    0
Utils/SparkError.h                             |10.9%    55| 0.0%   6|    -    0
Utils/SplineMath.cpp                           |20.5%    39| 0.0%   5|    -    0
Utils/SplinePath.h                             |    -     0|    -   0|    -    0
Utils/StackTrace.h                             |10.8%    74| 0.0%   8|    -    0
Utils/StateMachine.h                           |85.9%    64| 0.0%  49|    -    0
Utils/StringUtils.h                            |18.1%   116| 0.0%  21|    -    0
Utils/Telemetry.h                              |20.6%   136| 0.0%  23|    -    0
Utils/ThreadDebugger.h                         |11.6%   199| 0.0%  23|    -    0
Utils/ThreadSafeQueue.h                        |27.5%    40| 0.0%  11|    -    0
Utils/Timer.cpp                                |19.4%    36| 0.0%   7|    -    0
Utils/Timer.h                                  | 100%     2| 0.0%   2|    -    0
Utils/TimerManager.h                           |18.6%   102| 0.0%  19|    -    0
Utils/Tween.h                                  |26.3%    38| 0.0%   6|    -    0
Utils/UUID.h                                   |43.2%    37| 0.0%  16|    -    0
Utils/Validate.h                               |    -     0|    -   0|    -    0
Utils/WineDetection.cpp                        |23.1%    39| 0.0%   9|    -    0

[/home/runner/work/SparkEngine/SparkEngine/SparkSDK/Include/Spark/]
IEngineContext.h                               |7300%     1| 0.0%   1|    -    0
ServiceInterfaces.h                            | 200%     3| 0.0%   3|    -    0
Version.h                                      |    -     0|    -   0|    -    0
================================================================================
                                         Total:|31.0% 34131| 0.0%  6k|    -    0

Per-Subsystem Coverage

Subsystem Lines Hit Coverage Threshold Status
AI 3716 942 25.3% 35%
Animation 905 277 30.6% 35%
Audio 0 0 0% 30%
Camera 0 0 0% 40%
Core 4882 2918 59.8% 40%
ECS 426 213 50% 40%
Editor 7411 3046 41.1% 25%
GameModules 6621 3231 48.8% 30%
Graphics 17004 8338 49% 30%
Networking 3554 2351 66.2% 35%
Physics 0 0 0% 35%
Scripting 283 80 28.3% 30%
Utils 9775 6050 61.9% 60%

Total: 50.3% (27446/54577 lines)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants