Skip to content

LumaCore: multi-instance safe diversion artifact (fixes second Steam session under Duo isolation) - #148

Open
Jonybien wants to merge 1 commit into
Midrags:mainfrom
Jonybien:fix/lumacore-multiinstance-diversion
Open

LumaCore: multi-instance safe diversion artifact (fixes second Steam session under Duo isolation)#148
Jonybien wants to merge 1 commit into
Midrags:mainfrom
Jonybien:fix/lumacore-multiinstance-diversion

Conversation

@Jonybien

Copy link
Copy Markdown

Problem

With Duo Steam Isolation (multiple concurrent steam.exe from one install), LumaCore fails to initialize in the second session. Diversion::PrepareAndLoad() overwrites the fixed \bin\lcoverlay.dll on every boot; while session 1 keeps that module mapped, Windows rejects the overwrite with ERROR_SHARING_VIOLATION (32). The 25x120ms retry loop cannot outlast a mapped module, so boot aborts.

The global lumacore\status.json / status.json.tmp pair has the same single-instance assumption: sessions race on the same swap file and a healthy instance overwrites a failed instance's diagnostics.

Fix

Turns the diversion copy into an immutable, content-addressed artifact:

<Steam>\bin\lcoverlay-<first16-hex-of-sha256(steamclient64.dll)>.dll

  • Published once via per-pid temp file + MOVEFILE_REPLACE_EXISTING; racing boots converge (loser validates identical bytes and reuses).
  • Reuse requires re-hashing the existing file, so truncated/tampered leftovers are transparently republished.
  • Never rewritten while any process may have it mapped; Steam updates naturally produce a new artifact name.
  • Deferred attempt-based prune sweeps stale artifacts/temp files (DeleteFileA simply fails on anything another session keeps mapped).
  • New unit:
    untime/DiversionStore.{h,cpp} (streaming SHA-256 + protocol, self-contained).

Status side: "pid" field added, swap temps are now status.json..tmp, each instance also writes lumacore\status..json, and dead-session status files are pruned (throttled). SteaMidra keeps reading the global status.json unchanged.

SetBinarySnapshot() was previously never called; it is now wired so diversion_path/diversion_file_sha report real values.

Config / rollback

oml [diversion] multiinstance = true # default; false restores stock fixed-name behaviour

Environment override without rebuilding: LUMACORE_MULTIINSTANCE=0|1.

Verification

  • Standalone test of the store (publish / reuse while locked with loader-like sharing semantics / corruption recovery): PASS; computed sha256 matches Windows CNG (GetFileHash) on a 26MB steamclient64.dll.
  • Live run, two simultaneous isolated Steam sessions: both reach hooks_complete with 42 hooks and 274 lua depots, sharing the same artifact:

--- status.<pid1>.json --- --- status.<pid2>.json --- startup_phase: hooks_complete startup_phase: hooks_complete diversion_strategy: content-addressed-multiinstance content-addressed-multiinstance diversion_path: bin\lcoverlay-86112382982fa855.dll (both)

Closes the multi-instance failure mode described above. Happy to adjust naming/flag defaults if maintainers prefer a different contract.

…essions

PrepareAndLoad() overwrote the fixed bin\lcoverlay.dll on every boot, so a
second steam.exe (Duo Steam Isolation) died in CopyFileA with
ERROR_SHARING_VIOLATION while the first session still had the module mapped.

- diversion copy now lives at bin\lcoverlay-<sha16>.dll, published once and
  never rewritten while mapped; concurrent sessions share it read-only
- atomic publication via per-pid temp + MoveFileExA; racing boots converge
- stale artifacts and temp files swept by a deferred prune (attempt-based,
  safe against files other sessions keep mapped)
- status.json gains a pid field plus a per-instance status.<pid>.json mirror;
  swap temp is per-process to stop cross-session races
- [diversion] multiinstance setting (default on) with LUMACORE_MULTIINSTANCE
  env override for rollback without rebuilding

Verified live with two simultaneous isolated sessions (both reach
hooks_complete, 42 hooks each, shared artifact) plus a standalone unit test:
published/reused-under-lock/corruption-recovery paths pass, sha256 matches
the Windows CNG oracle.
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.

1 participant