Repository navigation
Offer a pinned USVFS stack-alignment fix for MO2 2.5.2 on ARM64 - #77
Merged
Merged
Conversation
Programs started through MO2 2.5.2 die on ARM64 because USVFS's injection stub calls InitHooks with a misaligned stack (ModOrganizer2/usvfs#93). This downloads ndabas's 0.5.6.1 backport of that fix, pinned by archive and per-file SHA-256, replaces only the four stock MO2 2.5.2 USVFS files, and keeps verified originals in <instance>/.modsync-usvfs/backup for Restore. Available from the dashboard, the Steam launch hub and `modsync mo2 usvfs status|apply|restore`; `doctor` reports it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Review fixes for the ARM64 USVFS workaround. - The "is MO2 closed" check matched command lines, so Steam's hook script, which waits on the launch hub with arguments ending in SkyrimSELauncher.exe, made Apply and Restore always fail from the hub. It also missed tools started from MO2 (xEdit, LOOT…). It now asks the host whether any of the user's processes maps this instance's USVFS files. Wine maps every DLL it loads from its Linux path; checked against MO2 under Proton Experimental on x86_64, where it is detected while running and clear after it exits. - restore() on an untouched instance returns "already in place" instead of failing for lack of a backup, without creating .modsync-usvfs. It also rechecks the files after the process probe, like apply(). - Download and unpack failures become UsvfsError, so the CLI and UI report them instead of a traceback. - Failures go out on a separate signal and show with the warning marker. - No hashing on machines where the fix can't matter (x86_64 without a backup); doctor hashes each instance once. - One guarded path for apply/restore in the service; _usvfs initialised in the dashboard instead of getattr checks. - README keeps only the dependency-table row; the prose stays in docs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
report.py used Path for the chosen instance's USVFS line without importing it, so `modsync doctor` and `diagnostics` raised NameError on the Steam Frame (and anywhere a USVFS backup exists) once ModSync had an instance. Found running the aarch64 Flatpak on a Frame. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
It depends on whether the machine has Steam and the game; CI has neither. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Without a Steam root doctor returns before the instance section. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Oct 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Programs started through MO2 2.5.2 die on ARM64 (Steam Frame): USVFS's injection stub calls
InitHookswith a misaligned stack, which real x86 tolerates by luck and FEX doesn't (#62). The fix is ModOrganizer2/usvfs#93, which is open and unreviewed, and no MO2 release carries it. Per the project's policy for non-MO2-LINT dependencies, ModSync carries its own workaround rather than waiting.What
v0.5.6.1-woa.1release: USVFS 0.5.6.1, the version MO2 2.5.2 ships, plus the stack-alignment fix. It stays statically linked, so it doesn't need the prefix VC++ runtime that USVFS 0.5.7+ does (Offer a current VC++ runtime in the game prefix for USVFS 0.5.7+ #66). The archive is pinned by size and SHA-256, and each of the four binaries by SHA-256.<instance>/.modsync-usvfs/backup. Restore puts them back and refuses to overwrite a build installed since. An interrupted replacement can be finished or undone. Unknown builds are left alone.modsync mo2 usvfs status|apply|restore, anddoctor. Shown on ARM64, or wherever a backup exists. Always an explicit click./proc/*/maps). Wine maps each DLL it loads from its Linux path, so this catches MO2 and every game or tool started from it. Steam's hook script waiting on the hub doesn't count, and neither does another instance.docs/usvfs-arm64.md(source commit, license, build workflow, validation plan). The README gets a dependency-table row only.Review fixes (second commit)
The first commit is the branch as written. The second fixes what review found:
SkyrimSELauncher.exe, so Apply and Restore always failed from the hub. It also missed tools started from MO2. Replaced with the memory-map check above..modsync-usvfs. It now reports "already in place". It also rechecks the files after the process probe, as Apply does.IncompleteRead, a bad proxy, 7-Zip errors) became tracebacks in the CLI. They'reUsvfsErrornow.doctorhashes each instance once.Testing
uv run pytest -q: 412 passed, 3 skipped. New tests run the real host probe against real processes: a process mapping the DLL blocks changes; a process whose arguments end inSkyrimSELauncher.exedoesn't; one mapping another instance's DLL doesn't.usvfs_x64.dllunder its Linux path. The probe blocks while MO2 runs and clears after it exits, at about 0.2 s per check.uv run pytest -q: 398 passed, 18 skipped. The skips are unrelated (no host xdelta3/7z, opt-in sync integration); the real-process probe tests ran and passed.Frame validation (third and later commits)
Done on a Steam Frame with the CI
flatpak-bundle-aarch64installed as the user's Flatpak:usvfs_x64.dllfrom/home/…/MO2-lint-test/usvfs_x64.dll, and so does every program it starts. The probe throughflatpak-spawn --hosttook 0.17 s. Apply/Restore were refused while MO2 ran, while Explorer++ or Skyrim was still alive after MO2 had been killed, and while both ran. They were allowed once everything exited. Lingeringnxmhandler.exe regand wineserver don't block, which is correct.inithooks in process 588 successfuland… 1240 successfulforSkyrimSE.exe(two runs), and the same for Explorer++. Explore Virtual Folder listed the mod's files inData. A new game started in the Realm of Lorkhan alternate start..modsync-usvfsuntouched.flatpak run --unshare=network … mo2 usvfs applyreinstalled from the cache. With no cache it failed cleanly and the instance was unchanged.modsync doctor/diagnosticscrashed withNameError: Pathon ARM64 once an instance was chosen (missing import inreport.py). Now covered by a test that runs with or without Steam on the machine.Closes #62.
Open question
The download comes from ndabas's fork release. If that release disappears, Apply stops working for anyone without a cached copy. Re-hosting the same archive as an asset on a ModSync release, with the same hash, would remove that dependency. GPL-3 allows it, and the source is linked. I haven't done it, because publishing a release is outward-facing.
🤖 Generated with Claude Code