For me usually on the 2nd try of starting a new game it does not disconnect.
The main issue I run in to is that the game gets stuck on the loading screen when resuming the campaign. It runs fine until I quit the game, after which I become unable to resume the campaign. I can however still start a new game.
Update: I think I found a workaround, disabling internet seems to allow me to launch a solo game.
The game also crashes any time I receive a Steam achievement.
Update 2: Actually, maybe the disabling internet trick does not work, and I just got lucky a few times.
Update 3: Disabling the Steam overlay solves the crashing issue. I managed to do a full playthrough with this workaround. Game may still crash on shutdown but otherwise works fine.
Just to be sure, you have the Proton EasyAntiCheat runtime installed, right?
Just to be sure, you have the Proton EasyAntiCheat runtime installed, right?
Sure, the install script will add it either way if you don't (my mistake this is false, the runtime isn't automatically installed). FWIW I can run other EAC games fine - Elden Ring and Hunt: Showdown from what I have installed atm. I guess I can try reinstalling the whole thing. You can run the game I presume?
For me usually on the 2nd try of starting a new game it does not disconnect.
Interesting. I'm getting 100% failure rate, always in the same spot when the camera shows the green goo cannister. Tried with various Proton versions probably 20 times.
I've cleaned the prefix and reinstalled EAC runtime but unfortunately the "Failed to connect" problem persists 😢
The install script for the game seems to correctly set up both EAC and EOS as far as file structure, although I couldn't find any specific logs from the process. FWIW I've also connected the game to the PROS account, seems that can't be easily disconnected again - might or might not be related.
At this point I'm out of ideas, hopefully someone chimes in. The perks of early access on Linux 😄
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2332663938
I was looking into getting regular version but it looks like the game devs didn't put on the game page that it uses Epic Online Service (Lots of bad reviews because of that) so maybe Steam wouldn't install it automatically, but if you are playing Hunt, you should have installed.
So for me using GE-proton 9-4 and turning cross play off under Game settings seems to make everything work fine.
started a new game and saw no disconnect message
Disabling Steam Overlay works! 🥳
(Settings > In Game > uncheck Enable Steam Overlay while in-game)
Finally could give it a try, and as the others, needed to disable Steam Overlay to make it work (Suck, because this games deserves getting some screenshots...) and crashing when closing it, have to stop it from the Steam client
This game seem to also affected by https://github.com/HansKristian-Work/vkd3d-proton/issues/1406.
launching the game with VKD3D_CONFIG=no_upload_hvv %command% have ~20% fps improvement for me.
Can confirm a performance improvements with that flag! :D
Can confirm a performance improvements with that flag! :D
didn't work here, on windows the difference is 30% , but i think the issue is the nvidia linux driver and directx 12 , not really related to proton.
I've encountered another issue with space marine 2. For some reason when certain light sources are present on screen, weird green and red artifacts can be spotted on the edge of the screen when moving the camera. Here is a video displaying the issue.
My specs:
✦ ❯ glxinfo | grep "OpenGL version" prints "OpenGL version string: 4.6 (Compatibility Profile) Mesa 24.0.7"the game launches but once the cutscenes stop and I'm about to be handed control over character the game freezes with weird graphical artifacts
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2349260726
looks like we have similar GPU + nixos, might that be some configuration problem with nixos?
Haven't seen any weird artifacts on the prologue and first level on:
7800X3D + 7800XT
Arch + Gnome + Mesa 24.2.2
Or at least didn't notice, but I see the last messages are all about artifacts and using Nixos, maybe something related to how mesa is build there? Are you using Proton Experimental?
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2350138190
yeah it's proton experinental. tbh its a pretty fresh install, im still trying to figure out how it's configured, i might be missing something
✦ ❯ glxinfo | grep "OpenGL version"
OpenGL version string: 4.6 (Compatibility Profile) Mesa 24.0.7
✦ ❯ glxinfo | grep "OpenGL version" OpenGL version string: 4.6 (Compatibility Profile) Mesa 24.0.7
That's kinda outdated mesa
Replying to [#8072 (comment)](https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2349260726)
looks like we have similar GPU + nixos, might that be some configuration problem with nixos?
Cant say, I havent changed anything bout my mesa config. This would be my config.
Haven't seen any weird artifacts on the prologue and first level on:
7800X3D + 7800XT Arch + Gnome + Mesa 24.2.2
Or at least didn't notice, but I see the last messages are all about artifacts and using Nixos, maybe something related to how mesa is build there? Are you using Proton Experimental?
I mainly see the artifacts when moving the camera, I thought maybe my GPU might be dying, but I experience no such artifacts in other heavy games. They only appear during fast mouse movement and only in indoor areas where warm light sources are present.
Haven't seen any weird artifacts on the prologue and first level on:
7800X3D + 7800XT Arch + Gnome + Mesa 24.2.2
Or at least didn't notice, but I see the last messages are all about artifacts and using Nixos, maybe something related to how mesa is build there? Are you using Proton Experimental?I mainly see the artifacts when moving the camera, I thought maybe my GPU might be dying, but I experience no such artifacts in other heavy games. They only appear during fast mouse movement and only in indoor areas where warm light sources are present.
Have no idea of Nix, you sure you using RADV and not AMDVLK right? I saw the env var to be setted correctly, but also AMDVLK installed?
Reply to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2351557454
AMDVLK is currently disabled on my system, games are running through mesa/RADV.
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2350082785
Got the exact same issue:
OS: Arch Linux
Host: ASUSTeK COMPUTER INC. ROG STRIX B650E-I GAMING WIFI
Kernel: 6.10.10-1-cachyos
Mesa: 24.2.2
Resolution: 2560x1440
WM: KWin
CPU: AMD Ryzen 7 7800X3D
GPU: AMD ATI Radeon RX 7900 XT/7900 XTX/7900M
Memory: 12176MiB / 64015MiB
For the moment got it to work switching to AMDVLK instead of RADV.
This game seem to also affected by HansKristian-Work/vkd3d-proton#1406. launching the game with
VKD3D_CONFIG=no_upload_hvv %command%have ~20% fps improvement for me.
Adding that flag has no affect for me on my Nvidia 3090 with Proton Experimental.
I am also getting a long hang and then crash whenever I quit the game. Most of the time I get this dialog message.
Other times I get the crash reporter.
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2357723450
To me on AMD game always crashes on exiting, have to stop it from the steam client. That flag helped me somehow for the game to make better usage of my CPU and GPU, if you were already CPU bounded it probably won't do anything.
I finished the campaign, what a bummer not to have the Steam Overlay, I would just non-stop make screenshots of it
To me on AMD game always crashes on exiting, have to stop it from the steam client. That flag helped me somehow for the game to make better usage of my CPU and GPU, if you were already CPU bounded it probably won't do anything.
The flag is for CPU bound. It trade gpu performance with cpu performance for some game, and it is for disabling rebar in vkd3d.
Check the issue https://github.com/HansKristian-Work/vkd3d-proton/issues/1406 for more information.
After 3.0 patch game doesn't playable in online mode. Looks like EGS services do not work anymore.
Online doesn't work on Proton 9.0-3 or Experimental or latest Proton-GE
After 3.0 patch game doesn't playable in online mode. Looks like EGS services do not work anymore.
Online doesn't work on Proton 9.0-3 or Experimental or latest Proton-GE
Not sure if because of not connection to EGS at all or if something fixed on the update, but the game is exiting fine now at least...
After 3.0 patch game doesn't playable in online mode. Looks like EGS services do not work anymore.
Online doesn't work on Proton 9.0-3 or Experimental or latest Proton-GE
Sigh.... Here they go again. It's really frustrating honestly. I was so excited for the new patch.
Steps I've taken:
Running OpenSUSE Tumbleweed, everything up to date.
Look like AVF error is not linux only problem.
There are few message said they have this error on windows example.
Most seem to be on linux/steam deck though.
Looks like everything that using online features doesn't work. Even PROS account. EGS account doesn't work too. PROTON_LOG=1 says nothing. Maybe there is another way to get some information.
I'm not sure if this is a good moment to get more info on the Steam Interface with the game, now the game can boot with the interface enabled, but it will just freeze when trying to open it
There's a bug report on their forum for the AVF error. Please upvote/comment if you're experiencing the same issue
Am also getting the AVF error, unable to use online play.
proton log: steam-2183900.log
sysinfo: https://gist.github.com/zaggynl/4d4649e98bcf1cf7b32a4945d6dec148
Update:
The response from the developer in the next message addresses the issues originally raised in this post now.
Dev just posted a announcement on discord that the issue linux/steam deck will be fixed next patch.
Regarding the black screen issue occurring on Oceania servers:
We are aware of it, the dev teams are on the matter at the moment.
We'll let you know when we get a fix.For the Linux/Steam Deck issue:
The next patch should fix the launch issue on Linux and Steam Deck.
<@&1242516345237798942>
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2393686524
No expected date for that patch?
@alosarjos Nope, just this.
No date yet.
Hotfix 3.1 is released.steam link.
Space Marine 2 - Hotfix 3.1
Hello Space Marines!We just pushed a small hotfix that brings various fixes. Thank you for your support!
Patch Notes
Fixed several crashes
Fixed heavy stutters on some CPUs
Fixed launch issue on Linux and Steam Deck
Fixed issue with dynamic resolution and ultrawide screens
Fixed issue with upscalers using wrong resolution parameters
Edit: Still getting AVF error. verifying game files.
Edit 2: Still getting AVF.
Edit 3:Adding env SteamDeck=1 seem to fix the online issue.From steam discussion
Yeah I just tried booting up in my lunch break. It works with the SteamDeck=1 variable. I can also run it alongside in gamescope by putting the variable in first. My env is SteamDeck=1 gamescope -h 1440 -r 165 --force-grab-cursor -- %command%
It's not the greatest fix, but it works I guess.
Edit: Note that the variable also sets all your in game settings to those optimised for the Steam Deck. If you were running on high graphics settings, they'll be turned down very low. I also don't know about people using Nvidia systems. There may be issues with DLSS, but I can't test this because I have an AMD GPU.
Works for me, and as previously said graphics are effectively nerfed...
Edit: Note that the variable also sets all your in game settings to those optimised for the Steam Deck. If you were running on high graphics settings, they'll be turned down very low. I also don't know about people using Nvidia systems. There may be issues with DLSS, but I can't test this because I have an AMD GPU.
DLSS works fine and AFAICT setting graphics settings back to ultra works, but will shoot out a warning about VRAM when doing so.
EDIT: It seems to be a Manjaro Problem: https://forum.manjaro.org/t/steam-games-wont-launch-after-2024-10-10-stable-update/169230
If someone has a solution, I will be happy anyways.
Unfortunality, the game does not work for me.
I only get a black screen and the game seems then to block my hole PC.
When I use gamescope with: SteamDeck=1 gamescope -h 1440 -r 165 --force-grab-cursor -- %command% as suggested by @LazyWings the game also just produces a black screen, but at least I can use my computer after the failed start attamped without rebooting.
I tried so far:
Computerinformationen:
Hersteller: Micro-Star International Co., Ltd.
Modell: X570-A PRO (MS-7C37)
Formfaktor: Desktop
Touch-Eingabe nicht erkannt
Prozessorinformationen:
CPU-Hersteller: AuthenticAMD
CPU-Marke: AMD Ryzen 7 5800X 8-Core Processor
CPU-Familie: 0x19
CPU-Modell: 0x21
CPU-Stepping: 0x2
CPU-Typ: 0x0
Geschwindigkeit: 4851 MHz
16 logische Prozessoren
8 physische Prozessoren
Hyper-Threading: Unterstützt
FCMOV: Unterstützt
SSE2: Unterstützt
SSE3: Unterstützt
SSSE3: Unterstützt
SSE4a: Unterstützt
SSE41: Unterstützt
SSE42: Unterstützt
AES: Unterstützt
AVX: Unterstützt
AVX2: Unterstützt
AVX512F: Nicht unterstützt
AVX512PF: Nicht unterstützt
AVX512ER: Nicht unterstützt
AVX512CD: Nicht unterstützt
AVX512VNNI: Nicht unterstützt
SHA: Unterstützt
CMPXCHG16B: Unterstützt
LAHF/SAHF: Unterstützt
PrefetchW: Nicht unterstützt
Betriebssystem:
"Manjaro Linux" (64 Bit)
Kernel-Name: Linux
Kernel-Version: 6.11.2-4-MANJARO
X-Server-Anbieter: The X.Org Foundation
X-Server-Release: 12101013
X-Fenstermanager: KWin
Steam-Laufzeitversion: steam-runtime_0.20240806.97925
Grafikkarte:
Treiber: AMD AMD Radeon RX 6800 XT (radeonsi, navi21, LLVM 18.1.8, DRM 3.59, 6.11.2-4-MANJARO)
Treiberversion: 4.6 (Compatibility Profile) Mesa 24.2.4-arch1.0.1
OpenGL-Version: 4.6
Desktopfarbtiefe: 24 Bit per Pixel
Monitor-Bildwiederholfrequenz: 165 Hz
Anbieterkennung: 0x1002
Gerätekennung: 0x73bf
Revision nicht gefunden
Anzahl Monitore: 1
Anzahl logische Grafikkarten: 1
Prim. Anzeigeauflösung: 2560 x 1440
Desktopauflösung: 2560 x 1440
Primäre Anzeigegröße: 27.44" x 15.43" (31.46" diag), 69.7cm x 39.2cm (79.9cm diag)
Primärer VRAM: 16384 MB
Soundkarte:
Audiogerät: USB Mixer
Arbeitsspeicher:
RAM: 32016 MB
VR-Hardware:
VR-Headset: Nicht gefunden
Sonstiges:
UI-Sprache: Deutsch
SPRACHE: de_DE.UTF-8
Verfügbarer Festplattenspeicher insgesamt: 937498 MB
Größter freier Festplattenspeicherblock: 270551 MB
Speicherplatz:
Anzahl SSDs: 3
SSD-Größen: 1000G,1000G,500G
Anzahl Festplatten: 0
Anzahl der Wechseldatenträger: 0
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2405735800
Hi - sorry, I've been busy so not been able to respond, but you found out it was a Manjaro/Arch problem unrelated to this. Hopefully that's resolved now. In future, you could maybe try the flatpak version of Steam if you run into any issues like that, until they get resolved.
More generally, I wanted to comment that the command I put is what works for me! I'm hoping most people know this but I know some people might just run into an issue and randomly start throwing out commands and environments they've copy pasted. I was quickly trying to get the game to work during my lunch break that day so just rushed out a response. I should have probably put: SteamDeck=1 gamescope [options] -- %command%.
For those that don't know:
-h sets the internal resolution height, defaulting to 16:9 if -w is undefined.-r sets the gamescope refresh rate. So that means my monitor is 1440p with 165hz refresh rate. You can launch gamescope at higher internal resolutions and such, but you'll just be wasting resources.--force-grab-cursor is something I use specifically for Space Marine 2 because there's a bug with multimonitor that breaks the cursor grab. I can still change window and free my cursor, but this just prevents the bug. I recommend it for SM2.gamescope --help in a terminal for a full list.I also should have clarified that the variable sets your graphics settings to what it considers Steam Deck optimised, but you can change it to whatever you want. I just didn't know whether it disabled DLSS or not, but seems like it just works and correctly recognises your graphics drivers, so it's all good.
Steam overlay is the only major outstanding issue for this game on Linux I believe. Which is weird because the Epic Games overlay works if you link your account.
Steam Deck LCD
SteamDeck=1 %command%
GE-Proton9-15
"SteamOS Holo" (64 bit)
Kernel Name: Linux
Kernel Version: 6.5.0-valve21-1-neptune-65-g33487bf05ed3
X Server Vendor: The http://X.Org Foundation
X Server Release: 12101011
X Window Manager: KWin
Steam Runtime Version: steam-runtime_0.20240806.97925
Video Card:
Driver: AMD AMD Custom GPU 0405 (radeonsi, vangogh, LLVM 16.0.6, DRM 3.57, 6.5.0-valve21-1-neptune-65-g33487bf05ed3)
Driver Version: 4.6 (Compatibility Profile) Mesa 24.0.5 (git-09d9c2fd7f)
game runs and appears to be stable, but the framerate is unbearable.
devs borked linux again, ever since WWZ this engine in particular struggles on linux smh, already tried 6.11, lts, same issue, crashes while loading a game, was working fine a few weeks ago, steamdeck=1 makes connection error go away but doesn't fix loading.
OS: EndeavourOS
GPU: Radeon RX 6700 XT
Kernel version: 6.12.0-rc1-1-mainline (6.11 or even lts 6.6 no difference)
Mesa version: 24.3.0-devel (doesn't matter, even stable crashes)
Desktop environment: KDE
Proton experimental, bleeding edge, proton-9, doesn't matter which proton version i use.
The game keeps freezing for me at the seizure warning screen. Anyone got a fix for this? I tried the cinematic skip launch parameter and the SteamDeck=1 environment variable without any luck.
EDIT: For some reason disabling cloud saves did the trick.
The game keeps freezing for me at the seizure warning screen. Anyone got a fix for this? I tried the cinematic skip launch parameter and the SteamDeck=1 environment variable without any luck.
EDIT: For some reason disabling cloud saves did the trick.
did you disable the steam overlay ?
The game keeps freezing for me at the seizure warning screen. Anyone got a fix for this? I tried the cinematic skip launch parameter and the SteamDeck=1 environment variable without any luck.
EDIT: For some reason disabling cloud saves did the trick.
As the person above said, disable Steam Overlay. Also turn off Mangohud and any other overlays you might have running. For some reason the only overlay the game likes on Linux is the Epic one. I also recommend Proton Experimental. I've found it crashes the least with that proton version. I've not tried GE9-16 but I had issues with GE9-15 and GE9-14.
This game seem to also affected by HansKristian-Work/vkd3d-proton#1406. launching the game with
VKD3D_CONFIG=no_upload_hvv %command%have ~20% fps improvement for me.
this isn't a solution and is more of a band-aid. It actually makes heavily CPU dependent scenes run with even less FPS. GPU utilization is a bit better but still far from perfect.
game is unlaunchable.
Debian Bookworm.
system info: https://gist.github.com/mathew2214/f75390c266e293080b8c44526849d8a2
proton logs: https://gist.github.com/mathew2214/a385727baff87d88fec697891ed9d4a2
Wanted to make more of a comprehensive report regarding a severe performance issue the game's had since launch on Proton. There's something wrong with GPU utilization on this game under Proton that results close to a 45% performance difference compared to how the game runs natively on Windows.
While I only have logs and screenshots as of the game's current version (Hotfix 5.1) running on my RTX 4070 Super, I know that while I was still running an RX 6700 XT I was having the same or similar issues back when the game first came out a few months ago.
VKD3D_CONFIG=no_upload_hvv only partially helps performance and it depends on the scene, so I don't believe Resizable BAR is the only culprit that's going on with this game regarding performance. Besides testing with that variable on and off, another confirmation for GPU utilization issues is that resolution scaling generally does not affect performance no matter what setting it's set to. Any lower resolutions simply lower GPU usage and power, and in some scenes it can actually cause a minor performance regression as shown in the later screenshots. These were all ran at Ultra preset with FSR upscaling set to Quality (barring the Ultra Performance comparison).
| Windows | Proton | Proton (no_upload_hvv) |
|---|---|---|
| Proton, FSR Ultra Performance | Proton, FSR Ultra Performance (no_upload_hvv) |
|---|---|
Proton log: steam-2183900.tar.gz
Proton (no_upload_hvv) log: steam-2183900_no-upload-hvv.tar.gz
If anyone else can help confirm this issue, would be greatly appreciated! Especially from AMD GPU users, because I don't have access to my RX 6700 XT anymore and can't directly find out if exactly the same issue and performance numbers are present there.
OS: "Fedora Linux 41 (KDE Plasma)" (64 bit)
GPU: NVIDIA GeForce RTX 4070 Super
Video driver version: NVIDIA 565.77
Kernel version: 6.12.4-200.fc41.x86_64
Link to full system information report as Gist: https://gist.github.com/CptCookies12/b2c753f8248d5c95cfe7f6dd0a87ac69
Proton version: experimental-9.0-20241217
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2553355068
Tested using a 6700xt with mesa-git vs windows 11 on a 5700X3D both with SAM on.
Game has terrible performance on windows/linux. gpu usage is lower on linux indeed, albeit with not so large performance differences, it trades blows all around.
So it doesn't affect AMD GPUs just as much but its definitely a tad slower than windows (it can be faster at times), another factor is the CPU bottleneck as well....
| Linux | Windows |
| Linux | Windows |
| Linux | Windows |
how are you guys getting the game to launch?
see https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2547299252
update: using GE-Proton8-32, the game launches, and i get to title screen, but it crashes as soon as i press enter.
proton log: https://gist.github.com/mathew2214/7646f8304f6bb914fa33e481e956286a/
attached is the zip file generated by the game's crash reporter. examining which is far above my skillset.
crash_data.zip
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2593697700
At least on a desktop, I disable the in-game overlay in the properties for the game on Steam.
Replying to [#8072 (comment)](https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2593697700)
At least on a desktop, I disable the in-game overlay in the properties for the game on Steam.
yeah, im doing it with steam overlay disabled. no difference.
I started playing the game again, now that it support 32:9 and I noticed that the issue I reported in my previous comment is still present. Has anyone encountered this?
using proton ge 10-3, i still cannot play the game on Debian.
proton log: https://gist.github.com/mathew2214/b2a895b4e4bda2e70961a98e23920ea0
system info: https://gist.github.com/mathew2214/af2665fd7772f408d506b518053466d1
using Valve's proton 10 also yields identical results.
valve, please fix.
This game will get slower and slower with FPS over time, starting with full 60fps i end up with average 45 FPS after doing 3 missions and the longer i play it becomes more and more unplayable. I tried on Windows and there are no FPS slowdowns over time with the same hardware.
It happens with all the Proton versions i tried, Proton experimental and Proton GE
PC Specs: AMD Ryzen 7 5800X3D , GeForce RTX 2080 , 32GB RAM
Looks like there is some kind of regression maybe on Proton Experimental with this game. I've been using the AMD stub to force FSR4 by using the DLL from AMD and FSR4_UPGRADE=1 with DXIL_SPIRV_CONFIG=wmma_rdna3_workaround
And this has been working perfectly for near more than a month, but now suddenly it started crashing the game. There have been no patches for the game in a month, but there was a Proton Experimental update a few days ago (Maybe yesterday?).
@alosarjos May be related https://github.com/HansKristian-Work/vkd3d-proton/pull/2679
Default build of vkd3d-proton now disable fp8 emulation by default.
FP16 version of fsr4 work though.
Really bad framerate drops since last patch. Not sure if a bug on the game, or something the game using now that has some issue on Proton.
Big fps drops and loading the game assets seems to be really broken after the last patch where loading screens take about 10x longer and switching your graphics settings take an eternity.
I expect this is down to the developers of the actual game tho
Big fps drops and loading the game assets seems to be really broken after the last patch where loading screens take about 10x longer and switching your graphics settings take an eternity.
I expect this is down to the developers of the actual game tho
I'm not reading about Windows users having theses issues...
There are some zones where Framerate will just do down forever. I took a screenshot showing how machine resources are not at full usage while having really bad framerate. Not sure if this helps somehow.
@alosarjos I think I'm seeing something similar, out of curiosity, does it still happen with EAC disabled?
if you don't already know how, the easiest way to disable it is to open the Warhammer 40000 Space Marine 2.ini file that's in the game's root directory and change ApplicationPath=start_protected_game.exe to ApplicationPath=client_pc\root\bin\pc\Warhammer 40000 Space Marine 2 - Retail.exe
@alosarjos I think I'm seeing something similar, out of curiosity, does it still happen with EAC disabled?
if you don't already know how, the easiest way to disable it is to open the
Warhammer 40000 Space Marine 2.inifile that's in the game's root directory and changeApplicationPath=Warhammer 40000 Space Marine 2.exetoApplicationPath=client_pc\root\bin\pc\Warhammer 40000 Space Marine 2 - Retail.exe
I will give it a try later. But sadly things have gone worse. On operations, I "only" get huge FPS drops, but on the waves survival mode, 3 times I tried playing, 3 times my GPU crashed putting me back on the Gnome login screen.
Worse thing about this is not knowing if it's a game issue, or a Linux issue.
Don't want to report issues for unsupported platform to devs
But neither want to report issues on mesa o VKD3D when all issues seems to come from the latest game patch
Any advice on how should I proceed @kisak-valve ?
Based off my testing, and assuming we have the same issue, I suspect EAC might be involved, after bypassing it (which launches the game in an offline/"modded" mode) I wasn't seeing any of the choppiness I was getting with it.
It's acting almost like I'd expect from a game on an HDD, despite being on my NVME
Space Marine 2 Fps loss after patch 11
Issue transferred from https://github.com/ValveSoftware/Proton/issues/9278.
@xarabenari-prog posted on 2025-12-03T15:11:43:
After patch 11, the game experiences huge frame rate drops for a few seconds before recovering.
It goes from a stable 70 FPS to 5-6 FPS for two or three seconds. Similarly, during moments of frame rate drop, the sound becomes choppy.
This happens frequently or when loading new environments or particles. I can't find a pattern to the cause.
I've tried various versions of Proton and different graphics settings, and I've also tried removing the shaders to force them to reload, but so far, no solution has been found.
Install the latest version of Space Marine 2 released on Steam and run it under the Proton compatibility layer.
Based off my testing, and assuming we have the same issue, I suspect EAC might be involved, after bypassing it (which launches the game in an offline/"modded" mode) I wasn't seeing any of the choppiness I was getting with it.
It's acting almost like I'd expect from a game on an HDD, despite being on my NVME
Good afternoon, I've tried the suggested solutions, and I can confirm that the FPS drop issue has been resolved. The problem now is that I obviously can't play online.
Thanks
@DrymarchonShaun My .ini was pointing to the start_protected_game.exe instead, but changed to the values you said, and yes, now it's running flawlessly. So yeah, related to the EAC, though I think it's affecting Linux way harder than Windows
Just stopping in to report that I also ran the test with disabled EAC to find the same results.
It is unclear to me who to report the issue to, exactly, so if there is another space we should be documenting this finding let me know.
Edit: recent hotfix did not resolve the issue for me.
I also asked my buddy on windows if he's been having any of the issues and there does appear to be a few specific places where this happens to him, so it may actually be a game issue that is worse for linux as noted above.
Still having same issues with Hotfix 11.1
Same issue here, fresh copy of Space Marine 2.
My system configuration:
OS: openSUSE Tumbleweed, Mesa 25.3.1 (from Packman repo), Kernel 6.18.0, ProtonGE 10.26
CPU: Ryzen 7 5700X@4700MHz all core, 1.35v fixed
RAM: 32GB DDR4 3600MT/s
GPU: MSI MECH RX 7600
All my games are installed in a nvme 1TB PCIe 4.0 with BTRFS as filesystem. When the game load the assets (it takes about 5 mins to load into the lobby) my audio starts crackling and all the cpu cores kick the %100 of usage.
No mather what configuration preset I use (Low, Medium, High), after 10 - 20 mins, my FPS drop from 120/140 to 35/50 fps depending on the number of enemies and map zones.
patch 11.2 released on steam. issue still persisting for me. (EAC enabled in order to play online) https://store.steampowered.com/news/app/2183900/view/492711197218439388?l=english
Debian 13. game is unlaunchable normally. i have to do the ini edit to run Retail exe in order for game to even start.
Game works with latest patch, but suffers from constant FPS drops (from 60 to single digits). When the game drops the GPU usage drops to almost 0% while CPU goes up to almost 100%. Also the game sometimes fails to launch due to EAC errors. Loading missions can take some time, but it might be due to networking issues
Game breaks pipewire on every loading.
Space Marine 2: Game freezes during cutscenes (NtGdiDdDDIQueryStatistics polling loop)
Issue transferred from https://github.com/ValveSoftware/Proton/issues/9368.
@taqd posted on 2026-01-04T08:48:27:
Game freezes completely during in-game cutscenes. When starting New Game or Continue, the intro cinematic begins and the game immediately becomes unresponsive. No keyboard or mouse input works (including Escape). No error messages or popups appear. The game must be force-killed.
Analysis of the Proton log shows a single thread (0224) stuck in a tight polling loop at 100% CPU:
0224:fixme:x11drv:X11DRV_D3DKMTQueryAdapterInfo desc 0x21cff570, type 3 stub
0224:fixme:driver:NtGdiDdDDIQueryStatistics (0x21cff8d0): stub
0224:fixme:driver:NtGdiDdDDIQueryStatistics (0x21cff8d0): stub
[repeats indefinitely]
The game's Streamline/DLSS integration appears to poll NtGdiDdDDIQueryStatistics for performance metrics. Since Wine returns nothing from this stub, the thread spins forever.
PROTON_ENABLE_NVAPI=0PROTON_HIDE_NVIDIA_GPU=1VKD3D_CONFIG=no_upload_hvvSteamDeck=1@taqd does this happen to mitigate your issue?
I think I'm seeing something similar, out of curiosity, does it still happen with EAC disabled?
if you don't already know how, the easiest way to disable it is to open the
Warhammer 40000 Space Marine 2.inifile that's in the game's root directory and changeApplicationPath=start_protected_game.exetoApplicationPath=client_pc\root\bin\pc\Warhammer 40000 Space Marine 2 - Retail.exe
worth noting, this means the game launches in offline/modded mode, so online play isn't possible and progress doesn't save. This can be reverted easily by editing the mentioned file back to what it was originally, however.
I tested Proton Experimental.
I played one round and defeated the Swarm Tyrant. There were significant performance drops during startup and loading screens, with the loading screen for the mission taking a particularly long time.
During the mission with other players, there were occasional freezes and stutters.
It has gotten better, but there is still a lot of room for improvement.
Space Marine 2: periodic main-thread stalls after Update 11 with EAC enabled (Proton regression)
Issue transferred from https://github.com/ValveSoftware/Proton/issues/9379.
@Kyrottimus posted on 2026-01-09T00:39:28:
• OS: Manjaro Linux (XFCE)
• Kernel: 6.6.119-1-MANJARO
• Desktop: XFCE 4.20 (X11)
• CPU: AMD Ryzen 9 7945HX (32 logical cores)
• RAM: 32 GB
• GPU: AMD Radeon RX 7600M XT (Navi 33)
• Driver: amdgpu (kernel)
• Mesa: 25.3.2-arch1.1
• Vulkan: 1.4.335
• Vulkan Driver: RADV (Mesa)
• OpenGL: 4.6 (radeonsi, LLVM 21.1.6)
Also, as a point of note, see
https://www.protondb.com/search?q=space marine 2
for a large number of other reports indicating the same symptoms described in this report.
Game
• Warhammer 40,000: Space Marine 2
• Regression introduced after Update 11
• Prior to Update 11, the game ran flawlessly under Proton on this system.
Description of the Problem
After Update 11, the game exhibits periodic main-thread stalls during missions when Easy Anti-Cheat (EAC) is enabled under Proton.
Observed behavior:
• Frequency: every ~30 seconds to 2 minutes
• Duration: typically 1–4 seconds (after mitigation)
• FPS drops to ~15–20 during stalls
• Complete input stall during events (mouse and keyboard unresponsive)
• GPU utilization drops during stalls but appears secondary
Disabling EAC removes the issue entirely, but there is no way to save progression in-game with EAC disabled so this is not an ideal solution.
Mitigation Findings
• CPU saturation significantly worsens stall severity
• Applying systemd CPUQuota reshapes behavior:
◦ Stall severity and duration are reduced
◦ Stall frequency increases
• Disabling frame generation removes input lag but does not remove stalls
• Alt+Enter temporarily clears the stall
• GPU-side mitigations do not resolve the issue
This strongly suggests a periodic EAC-related memory or synchronization operation blocking the game’s main thread, likely introduced by Update 11’s “memory handling improvements”.
Reproduction Steps
1. Launch Space Marine 2 under Proton with EAC enabled
2. Enter any mission, play through mission.
3. Observe periodic stalls during gameplay
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-3726575632
Note: the issue I reported was auto-merged here, but the symptoms are different from the original description.
My experience is not a connection/authentication failure — the game loads + runs under Proton Experimental, but after Update 11 which was released for Space Marine 2 on November 25, 2025, it exhibits periodic main-thread stalls while playing missions with EAC enabled:
• Frequency ~30s – 2min
• Duration ~1–4s
• Input freezes + FPS drops
• Disabling EAC eliminates the problem
• CPU scheduling mitigations reshape but do not remove the stalls
• Extensive log attached previously shows high resource churn and view map pressure under DX12 + vkd3d
This appears to be a performance regression after Update 11, not the original connection issue.
I can provide additional logs or traces if helpful.
I am using an AMD CPU and GPU, and tried disabling SMT in my bios. It did not fix the performance drops, but hte load times were much more stable and the performance drops did not last as long or occur as frequently. This might be a workaround for the time being.
CachyOS
GPU - 5700 XT
CPU - 3600
Ever since Update 11, I haven't been able to play online. Whether I'm in Public or Private, the game says I'm running mods (I've never used a mod on this game) and kicks me out of the 'public' game - even if I'm in Private. I can only play Solo.
And apparently I'm not the only one. Both the Steam Forums and the Focus forums are full of people reporting this. It does not appear to be associated with the AZW servers being unstable, which was what got the blame for this pre-U11. But afaict, all the reports of perma-Mod Detected since U11 appear to be Linux users. And Focus appears to be either uninterested or incapable in fixing it, despite the issue seeming to be directly caused by U11 detected Proton as a false positive for mods.
Note: the issue I reported was auto-merged here, but the symptoms are different from the original description.
@Kyrottimus you might already know this, but issues in this repo are per-game, not per-bug. So any issues related to SM2 go in this issue, even if the original reason the issue was created is different from what you are experiencing. The more recent comments in this thread are discussing the issue you are dealing with.
Is there any other news regarding to this game? I find hard to believe it's a 100% issue on the game or everyone would be unable to play this for months already...
Is there any other news regarding to this game? I find hard to believe it's a 100% issue on the game or everyone would be unable to play this for months already...
Nothing working on live as far as i know however there is a pts up for the new patch. Looking through the notes aside from memory and stability fixes i couldn't see anything about eac issues.
Pts notes here: https://community.focus-entmt.com/focus-entertainment/space-marine-2/blogs/339-pts-patch-notes-12-0
Space Marine 2 (AppID 2183900) on Linux regressed with Patch 11 on my setup: very long loading
times, severe frame drops/stutter (especially cutscenes), and occasional crashes.
Performance improved substantially with GE-Proton and split-lock mitigation workaround, but stability
is still not perfect.
x86/split lock detection: #AC: Warhammer 40000 ...NVRM: Xid (PCI:0000:01:00): 13, pid=..., name=Warhammer 40000, Graphics Exception ...kernel.split_lock_mitigate=0 while Steam game process is runningkernel.split_lock_mitigate=1 on exitThis significantly reduced load-time stalls and improved in-game/cutscene smoothness, but did not
fully eliminate crashes.
I had an issue when game used 100% of my CPU and render like 5-7 fps. Disabling split lock mitigation fixed that issue. Previously I used gamemode that can disable it automatically, so I never seen this before I switched to falcond.
EAC issue with high CPU usage and FPS drops on loading before and mid-game still persists as of patch 12.0.
A combination of scx_bpfland, gamemode and proton-cachyos-slr reduced stuttering to 2-3 seconds on average per PvE match. High CPU usage and load times are still abysmal compared to what was before patch 11.0. The main culprit is still EAC.
|
-- | --
OS | CachyOS (KDE Plasma Desktop Edition)
Session | Wayland
Kernel | 6.19.5-3-cachyos
Scheduler | scx_bpfland
CPU | AMD Ryzen 7 5800X
RAM | 32 GiB
GPU | NVIDIA GeForce RTX 5070 Ti
NVIDIA Driver | 590.48.01
Proton Version | proton-cachyos-10.0.20260207-slr
On initial load into a mission, the CPU is pegged at 100% utilization and the framerate drops to 5–7 FPS. The game does not recover on its own — it stays in this degraded state indefinitely.
A full game restart resolves the issue immediately and completely. Performance returns to normal for the next mission. The workaround is 100% reliable.
Additionally, during loading screens, audio crackling/popping is consistently audible. This may be related to the same underlying CPU usage spike.
I also experience the stuttering issues reported by other users in this thread.
Expected: Game loads into mission with watchable cutscene and playable perfomance Actual: CPU maxes out, game is unplayable. Restart required after every mission.
scx_cosmos fixed pretty much all stuttering for me. Pure magic!
scx_cosmos fixed pretty much all stuttering for me. Pure magic!
Can also confirm that using scx_cosmos scheduler fixed the stuttering for me too.
I implemented the the following on NixOS:
# Services
# https://search.nixos.org/options?channel=unstable&show=services
services = {
# Services - SCX
# https://search.nixos.org/options?channel=unstable&show=services.scx
scx = {
# Services - SCX - Enable
# https://search.nixos.org/options?channel=unstable&show=services.scx.enable
enable = true;
# Services - SCX - Scheduler
# https://search.nixos.org/options?channel=unstable&show=services.scx.scheduler
scheduler = "scx_cosmos";
};
};
I'll try the cosmos scheduler, I'm currently using lavd.
scx_cosmos fixed pretty much all stuttering for me. Pure magic!
Do you use any custom flags for cosmos or just the defaults?
Do you use any custom flags for cosmos or just the defaults?
Anecdotally, switching to scx_cosmos (with otherwise default settings FWIW) does appear to fix the biggest issue I was seeing.
It does still feel like it runs overall a little less well than it does on windows but "slightly slower" is much more playable than "randomly runs at 1fps for 5-15s at a time".
It is a strange workaround though, as there was also a data point saying that turning off the anticheat also resolves the issue (albeit removing the ability to multiplayer).
Combined with this discovery it indicates that the anticheat is potentially having some sort of issue that scx_cosmos mitigates?
It might be interesting to see which (if any) other schedulers also mitigate/resolve this issue, and if so (or not), potentially identify why.
Is something causing some kind of absolute worst case result in the default scheduler, or does scx_cosmos do something that happens to mitigate it?
After 1hr of gameplay I can confirm that the cosmos scheduler mitigates almost all the current issues. No more audio crackling while loading mission assets, no more low fps or drops. CPU usage in all cores is consistent during the gameplay with no performance degradation. I don't have any custom flags for cosmos.
Operating System: openSUSE Tumbleweed 20260304
KDE Plasma Version: 6.6.2
KDE Frameworks Version: 6.23.0
Qt Version: 6.10.2
Kernel Version: 6.19.5-1-default (64-bit)
Graphics Platform: Wayland
Processors: 16 × AMD Ryzen 7 5700X 8-Core Processor
Memory: 32 GiB of RAM (31.3 GiB usable)
Graphics Processor: AMD Radeon RX 7600
Interesting, I'm seeing the same thing. I just set up scx_cosmos and the game just... works.
Since some of y'all seem to be more familiar with it, is there any downside to just using scx/sched-ext all the time?
EDIT- actually, I think it may just be that the game is working now, even without any of the schedulers the game seems to be running fine for me.
Interesting, I'm seeing the same thing. I just set up scx_cosmos and the game just... works.
Since some of y'all seem to be more familiar with it, is there any downside to just using scx/sched-ext all the time?
I don't see any issue here by using a custom scheduler, cosmos can handle different types of workloads, it's a general purpose scheduler.
I can also say that using the scx_cosmos scheduler works on my end. Using CachyOS with AMD an AMD 3600 CPU and 5700 GPU.
I can also say that using the scx_cosmos scheduler works on my end. Using CachyOS with AMD an AMD 3600 CPU and 5700 GPU.
Did you happen to check if it still wasn't working without scx_cosmos?
For those monkeys like me on non cachy arch distros and trying to find a "simple" way to implement changing your scheduler :
Install:
sudo pacman -S scx-scheds
Once installed, simply run this in terminal before starting the game:
sudo scx_cosmos
Leave the terminal open the whole time, you can ctrl+c to close it afterwards if you don't want the scheduler to be changed all the time.
edit: can confirm, game is completely playable with the new scheduler running.
Did notice that as the game stays open, performance degrades over time until you restart the game, might be NVIDIA specific though.
Fixed problem
Space Marine 2 crashes/freezes immediately after the first cutscene (story_intro scene) on Linux with
NVIDIA RTX 5000 series GPUs. The game menu works fine, EasyAntiCheat loads successfully,
but the GPU hangs during gameplay load.
Root cause: NVIDIA driver bug (Xid 109 — CTX SWITCH TIMEOUT). Certain compute shaders in SM2 use SPIR-V
instructions that the Blackwell GPU driver can't handle, causing a context switch timeout.
How to confirm you have this issue:
journalctl -b --no-pager -p warning | grep -i "xid"
You'll see:
NVRM: Xid (PCI:0000:01:00): 109, pid=XXXXX, name=Warhammer 40000, channel 0x0000000a, errorString CTX
SWITCH TIMEOUT, Info 0xc006
The Fix: pyroveil
Pyroveil is a Vulkan layer that rewrites problematic shaders through SPIRV-Cross, making them
compatible with the NVIDIA driver.
sudo pacman -S ninja cmake gcc git
git clone --recursive https://github.com/HansKristian-Work/pyroveil.git ~/pyroveil
cd ~/pyroveil
mkdir -p build
cd build
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/.local
ninja
ninja install
{
"version": 2,
"type": "pyroveil",
"matches": [
{ "spirvExecutionModel": 5, "action": { "glsl-roundtrip": true } }
],
"roundtripCache": "cache",
"disabledExtensions": [ "VK_NV_raw_access_chains" ]
}
Then create the cache directory:
mkdir -p ~/pyroveil/hacks/space-marine-2-nv/cache
PYROVEIL=1 PYROVEIL_CONFIG=~/pyroveil/hacks/space-marine-2-nv/pyroveil.json DXVK_ASYNC=1 %command%
What this does:
Environment tested on:
Notes:
More detail:
The problem is that VKD3D-Proton generates valid but unusual SPIR-V patterns (especially around subgroup/wave operations in compute shaders) that NVIDIA's Windows driver never sees. The Blackwell driver's SPIR-V compiler has a bug where certain patterns cause the GPU to hang during context switching.
Pyroveil fixes it by roundtripping the SPIR-V through SPIRV-Cross (decompile to GLSL, recompile back to SPIR-V). This produces equivalent but more "conventional" SPIR-V that the driver handles fine.
Warhammer 40000 Space Marine 2 wont run on 2nd SSD
Issue transferred from https://github.com/ValveSoftware/Proton/issues/9585.
@target-bravo posted on 2026-03-17T13:50:35:
Game will not launch when installed to the second NVME on my system and will give the error "failed to get process path" from easy anticheat, but it will launch when installed on the system SSD. all other games installed on the second SSD run well claire obscura, sniper elite 5, helldivers 2 etc
I have reinstalled steam os and done a complete wipe of the second ssd and the issue is identical. wierd secondary issue with steam is that the game will not move between locations i have to uninstall and install each time as it declares that a file is busy.
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-4075172775
I forgot to add that the game was working on the second SSD to which i did about 1/2 a second playthrough then after about 2 steam OS updates it would give me the error
Hello @target-bravo, can you check how the game behaves with the game's launch options set to PROTON_SET_GAME_DRIVE=1 %command%? (from https://github.com/ValveSoftware/Proton/issues/1651#issuecomment-3814151296)
Hello @target-bravo, can you check how the game behaves with the game's launch options set to
PROTON_SET_GAME_DRIVE=1 %command%? (from [#1651 (comment)](https://github.com/ValveSoftware/Proton/issues/1651#issuecomment-3814151296))
Same issue sadly
Ok i think i have it sorted after 3 days of trial and error.
I previously set up a folder /run/media/deck/Games/ then setup the drive to mount to this location in KDE partition manager like SD-Cards.
when like this the game would give me the above error.... but only recently for some reason
I then unmounted the drive removed the folder and that mount point from kde partition manager and double clicked the drive to mount it.
Space Marine 2 now launches fine but the drive does not auto mount anymore.
Now for the weird fix mounting the drive by double clicking creates a folder /run/media/deck/Games/ same as above. Now if i use this folder in KDE Partition manager as the mount point Space marine 2 will launch just fine.
- Fixed an issue causing low FPS and 100% CPU usage on Steamdeck.
Interested to see if this will resolve the FPS and CPU issues on Linux in general, without the use of a custom scheduler.
Time to test
- Fixed an issue causing low FPS and 100% CPU usage on Steamdeck.
Interested to see if this will resolve the FPS and CPU issues on Linux in general, without the use of a custom scheduler.
Just completed the weekly normal, no issues. Looks like its fixed.
Game performance still unfortunately degrades over time, at least for Nvidia GPUs(590 driver.) After a couple missions performance will slowly get worse until you restart the game.
Better than it was, but still not perfect.
https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-4071848316 - legend for posting this.
Game performance still unfortunately degrades over time, at least for Nvidia GPUs(590 driver.) After a couple missions performance will slowly get worse until you restart the game.
Nvidia driver 595.58.03
Operating System: Bazzite 43
KDE Plasma Version: 6.6.3
KDE Frameworks Version: 6.24.0
Kernel Version: 6.17.7-ba29.fc43.x86_64 (64-bit)
Graphics Platform: Wayland
didn't notice this issue. could be related to kernel/shell? in other games i noticed some settings like the vsync mess with frame timing which causes stutters at times. maybe there's an optimal way to configure the game?
Unfortunately running the pyroveil "hack" does nothing but absolutely nuke my framerate. Updating all my packages recently still doesn't help with performance degradation, after about 2 missions i notice a subtle hit, after about 3-4, frametimes are toast and the game needs restarted. Seems to accelerate if you spend a lot of time in the armory.
Garuda Linux x86_64
Kernel: 6.19.11-zen1-1-zen
Resolution: 3440x1440 2560x1440 1920x1080
DE: KDE Plasma 6.6.4
WM: KWin (Wayland)
WM Theme: Sweet-Dark
Theme: Dr460nized (Sweet) [Qt], Sweet-Dark [GTK2/3/4]
Icons: BeautyLine [Qt], BeautyLine [GTK2/3/4]
Terminal: konsole 25.12.3
Terminal Font: FiraCode Nerd Font Mono 12
dCPU: AMD Ryzen Threadripper PRO 5975WX 32-Cores (64) @ 4.561GHz
GPU: GeForce RTX 4090
GPU: ASPEED Graphics Family
Memory: 12349MiB / 257575MiB
Running the journal command
journalctl -b --no-pager -p warning | grep -i "xid"
Returns nothing, so i'm assuming i don't share the same issue.
I use these launch options normally:
PROTON_USE_NTSYNC=1 gamemoderun __GL_SHARPEN_ENABLE=1 __GL_SHARPEN_VALUE=100 PROTON_HIDE_NVIDIA_GPU=0 PROTON_ENABLE_NVAPI=1 PROTON_NVIDIA_LIBS=1 %command%
Using latest proton GE.
Playing the game on windows for now without any issues, here's hoping it sees some improvement eventually.
Unfortunately running the pyroveil "hack" does nothing but absolutely nuke my framerate.
GPU: GeForce RTX 4090
In my albeit small experience this hack is exclusively for 50x Nvidia series.
Have you tried Proton EM latest?
I've tried other proton versions but i haven't heard of proton-em, what makes it different from GE/Cachy/stock? The github doesn't really go into detail.
@Zeronthe i can't really tell. i've seen this in the tinker steps on protondb and during my attempts to launch the game i basically landed on the combo of this hack + proton EM latest. the version itself is available through the usual means on bazzite - protontricks, so seems legit enough
Unfortunately using proton-EM didn't do anything to resolve the issue here. After the third mission, like clockwork, performance started to degrade.
Proton Log: steam-2183900.log.gz
Hello,
a new problem with this game has arisen for me. Up until about 2 weeks ago, I could play the game as usual. When I tried to play again yesterday, I couldn't reach the main menu anymore. The game starts, the "intro" videos play, shaders are precreating when cleaned, then the game will hang anytime before reaching the main menu. The "send report" dialog then appears after some time and the game exits upon answering the dialog box.
The driver error: "kernel: NVRM: Xid (PCI:0000:0c:00): 13, pid=2704, name=Warhammer 40000, Graphics Exception: channel 0x0000000b, Class 0000c997, Offset 00000000, Data 00000000", meaning that a GPU shader or compute kernel triggered an exception during execution.
Verifying files shows no error.
As the last successful game session was using previous NVIDIA driver version, I tried downgrading nvidia packages to last known good (595.71.05), cleaning shader caches and vkd3d-proton.cache files and rebooting, to no avail, same error.
I also tried the pyroveil route to counter some potentially problematic shaders, same error.
What was updated since last known good:
Run the game, and have the game crash anywhere near intro cinematics and main menu (instant depends if you skip videos or not).
The driver error: "kernel: NVRM: Xid (PCI:0000:0c:00): 13, pid=2704, name=Warhammer 40000, Graphics Exception: channel 0x0000000b, Class 0000c997, Offset 00000000, Data 00000000", meaning that a GPU shader or compute kernel triggered an exception during execution.
I had the same issue. Using these launch options (4k monitor)
gamescope -W 3840 -H 2160 -f -- %command%
and Proton Experimental got me into the main menu
I had the same issue. Using these launch options (4k monitor)
gamescope -W 3840 -H 2160 -f -- %command%and
Proton Experimentalgot me into the main menu
No joy for me :(, same crash with gamescope.
After some tries, it seems the game does not crash if I set the game refresh rate to 60Hz or 90Hz:
gamescope -W 3840 -H 2160 -r 60 -f -- %command% has let me reach past the crashing point.-r 120 or -r 240, --adaptive-sync or not crashed every time.gamescope -W 3840 -H 2160 -r 90 -f -- %command% then removing the launch options: game works again.So if you encounter the same bug: FPS limit to 90 may help.
Game has frame pacing issues on Intel hybrid CPUs.
Easily testable in-game in the hangar lobby, panning visual left-right.
I solved it on my setup using taskset to restrict it on P-Cores only.
taskset -c $(cat /sys/devices/cpu_core/cpus) %command%
Can this be integrated in Proton itself?
ty in advance
i7-13700K
RTX 4070 Ti
Proton Experimental
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-4595147633
I have encountered the same deal. I was able to play a few days ago and today I could not reach the main menu, when I press enter it crashes.
RTX 3080 / R7 5700x3D / CachyOS
I was able to get in by using this launch option.
VKD3D_CONFIG=descriptor_heap PROTON_VKD3D_HEAP=1
Hi
I've found quite interesting issue with the game i need to fully confirm this with more testing but on my end no matter the proton version game freeze at every even hour. I'm not quite sure what reason might be and is it just my configuration related, maybe its new mesa version that my os got like a week ago, or something related with proton.
I'm looking for some guesses/ideas what this might be.
my specs:
Operating System: PikaOS 4
KDE Plasma Version: 6.5.4
KDE Frameworks Version: 6.20.0
Qt Version: 6.9.2
Kernel Version: 7.1.4-pikaos (64-bit)
Graphics Platform: Wayland
Processors: 16 × AMD Ryzen 7 5700G with Radeon Graphics
Memory: 32 GiB of RAM (30.7 GiB usable)
Graphics Processor 1: AMD Radeon RX 6700
Graphics Processor 2: AMD Radeon Graphics
thanks for any response in advance.
edit:
I've tested whether this might be somehow related to some service since it was weird that freeze always happened at even hours, but it's not related to any service i wonder whether its not something related to EAC runtime, but I'm not sure
Space Marine 2 crash mid-mission
Issue transferred from https://github.com/ValveSoftware/Proton/issues/10020.
@Ferrum115 posted on 2026-07-31T08:01:40:
Proton log (I closed the game manually before the crash):
proton-log-2183900.zip
Mid-mission game throws crash message, then freezes until being closed manually. No freezes/lags/multiplayer desync/graphical artifacts before, just crash window out of the blue. Character is controllable around a minute after, then the game freezes.
steam-2183900-updated.zip
Updated proton log file, now containing freeze moment
Adding concrete evidence tying the periodic EAC main-thread stalls (previously tracked separately at #9379, merged here) to a specific, easily-measurable symptom: the controller goes completely dead during each stall, not just mouse/keyboard as reported before.
System: Bazzite (Fedora Atomic) desktop, kernel 7.2.0-ogc4.1.fc44.x86_64, AMD GPU (RADV), Proton-GE (latest), Steam Controller (Valve's own wireless "Puck" dongle, not a third-party pad).
Symptom: Mid-session, all controller input to the game stops entirely - only the Steam-button chord (handled by the Steam client itself, outside the game's input path) still works, confirming it's not a physical disconnect. Also hit a crash on exiting a level (matches earlier reports here from 2024 of crash-on-quit).
Concrete evidence of periodicity, pulled directly from the kernel log during one session:
$ journalctl -k --since "22:05:00" | grep "X-Box 360 pad"
Aug 24 22:05:39 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input71
Aug 24 22:07:36 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input72
Aug 24 22:07:42 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input73
Aug 24 22:09:48 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input74
Aug 24 22:11:51 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input75
Aug 24 22:12:54 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input76
Aug 24 22:14:14 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input77
Aug 24 22:16:10 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input78
Aug 24 22:16:21 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input79
Aug 24 22:17:21 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input80
Aug 24 22:17:45 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input81
Aug 24 22:18:21 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input82
That's Steam Input's virtual XInput device (uinput) being torn down and rebuilt roughly every 60-90 seconds, continuously, for the whole session - lining up closely with the "~30s to 2min" stall interval reported at #9379. My read: Steam Input is reactively rebuilding its virtual controller device each time it perceives the game/its input path as unresponsive during an EAC stall, which is why the controller (not just mouse/keyboard) goes fully dead each time.
Tried the usual Steam Input remedies first (forcing an Xbox-360-emulating controller layout instead of the native template) - confirmed via ~/.local/share/Steam/logs/controller.txt that this had zero effect on the underlying churn, so this isn't a per-game Steam Input config issue, it's downstream of the EAC stall itself.
Happy to grab a PROTON_LOG=1 capture or anything else useful if it'd help narrow this down further.
Correction to my comment above: I connected the controller churn to the EAC periodic-stall pattern based on a rough timing match, but further testing shows that's likely wrong. During the same kind of session, the game itself (framerate, rendering) ran smoothly the whole time with no stutter or freeze - only the controller went unresponsive, repeatedly. That doesn't match the "everything stalls together" symptom described for the EAC main-thread-stall issue, so I don't think these are the same bug. Apologies for the noise - leaving the kernel-log evidence above since the churn itself is still real and reproducible, just not (as far as I can tell) tied to the EAC stall specifically.
WH40K - Space Marine 2 Anti-Cheat Issue
Issue transferred from https://github.com/ValveSoftware/SteamOS/issues/2765.
@cptcruisectrl-ops posted on 2026-08-29T19:36:04:
Describe what you expected should happen and what did happen.
Ran Space Marine 2 on Proton Experimental on 3.8.26. Anti-cheat worked fine. Running on 3.9.0 gives an error - Launch Error: Unexpected error (#1). Switched to Proton 11.0-2 and works fine. Just seems to be a problem with Proton Experimental.
Easy Anti-Cheat launch failure on Proton Experimental/Hotfix (Unexpected error. (#1)) & Patch 14.1 Texture Streaming Crash
Issue transferred from https://github.com/ValveSoftware/Proton/issues/10111.
@Esenych posted on 2026-09-01T14:08:52:
There are two major issues:
Launch failure on Proton Experimental & Proton Hotfix:
The game fails to launch entirely when using official Proton Experimental or Proton Hotfix. Easy Anti-Cheat halts initialization with the popup error:
"Ошибка запуска: Unexpected error. (#1)"
The game currently only bypasses EAC and starts when using GE-Proton 11-5.
Texture Streaming pool overflow / Crash on Patch 14.1 (GE-Proton 11-5):
After 190+ hours of stable gameplay prior to Patch 14.1, reproducible crashes occur during extended play sessions (e.g. Operations / hm_fortress map). The engine triggers an unhandled exception / Crash Dump Sending Utility because the Texture Streaming allocator exceeds its assigned budget without triggering mipmap drops/eviction (0.0 mips drop).
Memory dump state at exception:
Title memory: 5887.6 / 11360.1 MB (3074.4 MB free)
GeomStreaming: 544.3 / 550.0 MB [Utilization: ~98.9%]
TexStreaming: 2065.3 / 2000.0 MB [OVERFLOW: +65.3 MB, 0.0 mips drop]
Reserved memory: 300.0 MB, 0.0 temp [MB]
Total Memory: 8168714240 bytes (~7.6 GB budget reported under Wine DXGI)
Free Host Memory: 26723504128 bytes (~24.8 GB)
Technical breakdown:
8168714240 bytes (~7.6 GB) on a 12 GB physical GPU, causing the game to set a tight 2000 MB limit for TexStreaming.TexStreaming exceeds this hard cap (reaching 2065.3 MB), but GC/eviction fails (0.0 mips drop), leading to an immediate Access Violation crash.For EAC Launch Error:
Unexpected error. (#1).For Streaming Pool Crash (GE-Proton 11-5):
hm_fortress / Decapitation).TexStreaming exceeds 2000 MB.Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-5142885754
Basically the same for me.
Space Marine 2 crash mid-mission
* GPU: AMD Radeon RX 7900 XTX [Discrete]
* Video driver version: Mesa 26.2.1-arch3.1
* Kernel version: Linux 7.2.2-1-cachyos
* Proton version: Proton 11, proton-cachyos-11.0-20260703, GE-11-5_x86
What I noticed is that when I disable FSR I get the weirdest error.
The result is the same but the crash utility does not show up.
Instead I get an error like:
A crash report cannot be display because (repeats itself) - popup window and click OK and it dies.
I also seeing the memory overflow above. Despite having 24GB VRAM it still limits itself hard.
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-5142885754
My game crashes after every 30mins, I've tried with vanilla proton 11, Proton cachyOS latest, Proton GE 11.5 and 10.34, nothing stops this from crashing.
What's the workaround?
Hi. Same problem here. For about a month now, it's suddenly started crashing mid-operation or near the end, before displaying the error message. I've tried Proton 9, experimental, and -GE, after deleting shaders at 2183900 first, and the same error always occurs.
system
Bazzite (KDE)
gpu:Radeon RX 9060 XT
cpu: ryzen 7 5700x
detalle completo
https://paste.centos.org/view/7f30a908
The log file is large (70MB), but this line seems to indicate the problem itself:
2513.719:00ec:00f0:trace:seh:dispatch_exception code=6ba (RPC_S_SERVER_UNAVAILABLE) flags=0 addr=00006FFFFFBFD947
I am having the same issues with an unexpected side effect.
Kernel 7.2.2-1-cachyos-bore
gpu RX7800XT, mesa 26.2.2
Tried proton versions: ge-proton10-34, proton9.0-4, proton-cachyos-11.0-20260703 (steam linux runtime), proton11.0-2, ge-proton11-6-x86_64, proton experimental.
Some of these do not start at all (Unexpected error #1), otherwise the game starts and randomly during Operations I will get the "Application has stopped working" popup. But, the game itself keeps running if I ignore that, only 'freezing' when transitioning (from operation to victory/failure screen).
Neither dmesg/journalctl/PROTON_LOG=1 seem to capture anything relevant; I had some "Intense view map pressure! Got 1024 views in hash map ..." but, after disabling Frame Generation they seem to have disappeared.
UPDATE: ge-proton11-5-x86_64 seems to reduce the frequency of this happening, but the crash is now "full" - the game does not "keep running" as described earlier, but just freezes.
Warhammer 40,000: Space Marine 2 dont start
Issue transferred from https://github.com/ValveSoftware/Proton/issues/10122.
@thefilip988 posted on 2026-09-06T05:33:02:
steam-2183900.log
here the same in gist https://gist.github.com/thefilip988/cb32391e202946b0e1b3eae83740b29e
stuck on *--cwd' 'client_pcrootbinpc' and not start
Kernel: Linux 7.2.2-1-cachyos
GPU: RTX 4080 Max-Q [mobile]
Proton version: proton-cachyos-11.0-20260703 (steam linux runtime)
"Continuation" on this issue: https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-5142885754
Attempt at sending crash report and crash window, held on surprisingly long after crash message appeared. Third stage on Siege mode.
The crashreport stays open until a new map section loads. Usually you will notice the loading zone (elevator) will have low resolution textures.
On steam the current suggestion is to clean out the shadercache of the game in the steam folder. Select Proton GE 11-5 (or default 11)and do not change any graphical setting after the new shader compilation.
I have yet to test longer. I was okay for 1 hour and about 30 minutes.
If anyone is looking for a workaround. This issue stopped for me when I downgraded my kernel from 7.2 to 7.1 on cachyos
If anyone is looking for a workaround. This issue stopped for me when I downgraded my kernel from 7.2 to 7.1 on cachyos
So, it's something with the new kernel version and an incorrect memory report from wine?
If anyone is looking for a workaround. This issue stopped for me when I downgraded my kernel from 7.2 to 7.1 on cachyos
So, it's something with the new kernel version and an incorrect memory report from wine?
I do not have enough knowledge in this area to be confident about what the issue is.
I worked through this with Claude: going through journalctl, coredumpctl, Proton logs, and eventually a kernel bisect.
Here is what Claude has to say about it:
"A reproducible EXCEPTION_ACCESS_VIOLATION at the same instruction address every time (0x14215902E), across multiple Proton versions (stock 11.0-2, Proton 10.x, and proton-cachyos), so it's not a Proton-specific bug. I also tested kernel 6.18.42 LTS and got the same crash there, so it's not simply "newer kernel = broken" — something specific changed between 7.1.8 and 7.2.0 that isn't present in either 7.1.8 or the LTS branch.
The crash address staying identical while the exception's secondary info value changes each time made us think it's more likely a timing/race condition (maybe ntsync or a scheduler change) than a straightforward bad memory report, but neither of us knows Wine/kernel internals well enough to confirm that. Been stable on 7.1.8 since."
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-5561397900
I downgraded my kernel to that version 7.1.8
I can confirm that this kernel has something else that prevents these crashes after playing 1 long siege match.
After 3hrs of heavy gameplay with 7.1.8, I got 0 crashes.
The workaround for now is to stick with 7.1.8, idk how this kernel manages to avoid these memory overflows with the texture streaming.
I only used proton-cachyos latest.
Using stock proton 11.0-2 and 7.1.11-zen1-1-zen kernel also produces no crashes. Got crashes on latest cachy and garuda kernels, though.
I've always had similar issues like these on the cachy-like kernels though, which is why i went back to zen as soon as i crashed when i was trying out the garuda kernel for the first time. They Always seem to be more trouble than they're worth, at least for my configuration.
If I could pursade you guys.
journalctl -b -p err after crash.
I did open a topic on https://discuss.cachyos.org/t/kernel-7-1-to-7-2-crashes-with-proton-space-marine-2/35399
Because it would be dandy to have this fixed asap. If I have the chance to experience a crash will do the same.
I think it's not specific to cachy's kernel, I tried it on openSUSE locking the 7.1.8 and it's the same result.
I think it's not specific to cachy's kernel, I tried it on openSUSE locking the 7.1.8 and it's the same result.
Same result as in not crashing I assume?
I would still like to have some crash logs I could escalate to the devs on the forum and hopefully then get a fix for the next kernel or a patch.
I think it's not specific to cachy's kernel, I tried it on openSUSE locking the 7.1.8 and it's the same result.
Same result as in not crashing I assume?
I would still like to have some crash logs I could escalate to the devs on the forum and hopefully then get a fix for the next kernel or a patch.
Yes 0 crashes.
I think it's not specific to cachy's kernel, I tried it on openSUSE locking the 7.1.8 and it's the same result.
Same result as in not crashing I assume? I would still like to have some crash logs I could escalate to the devs on the forum and hopefully then get a fix for the next kernel or a patch.
Transparency note: this investigation was done with help from Claude via the browser chat interface. Claude had no access to my machine; I ran every command and pasted the output in. Its role was suggesting diagnostic steps, interpreting logs, and structuring this write-up.
@Legion495 Here's the journalctl -b -p err output you asked for. It's from a crash-loop on 2026-09-06, which happened on kernel 7.1.8 (the one I'd otherwise found stable), not on 7.2.0. Details on that below.
Sep 06 22:24:12 kernel: NVRM: GPU at PCI:0000:01:00: GPU-dc9ccec1-be76-2ac3-5938-b59e99f1242e
Sep 06 22:24:12 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=12770, name=Warhammer 40000, Graphics Exception: channel 0x00000009, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 22:25:44 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=13692, name=Warhammer 40000, Graphics Exception: channel 0x0000000a, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 22:27:32 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=14559, name=Warhammer 40000, Graphics Exception: channel 0x0000000a, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 22:45:12 kernel: NVRM: GPU at PCI:0000:01:00: GPU-dc9ccec1-be76-2ac3-5938-b59e99f1242e
Sep 06 22:45:12 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=4979, name=Warhammer 40000, Graphics Exception: channel 0x00000007, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 23:26:48 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=9928, name=Warhammer 40000, Graphics Exception: channel 0x00000007, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 23:29:34 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=10835, name=Warhammer 40000, Graphics Exception: channel 0x00000029, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 23:38:18 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=12816, name=Warhammer 40000, Graphics Exception: channel 0x00000007, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 23:40:14 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=13739, name=Warhammer 40000, Graphics Exception: channel 0x00000007, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 23:42:14 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=14730, name=Warhammer 40000, Graphics Exception: channel 0x00000007, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 23:47:14 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=16061, name=Warhammer 40000, Graphics Exception: channel 0x00000008, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 23:48:54 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=16938, name=Warhammer 40000, Graphics Exception: channel 0x00000008, Class 0000c997, Offset 00000000, Data 00000000
Xid 13 is a Graphics Engine Exception: the GPU rejected a command buffer containing an invalid instruction or illegal memory access. Class 0000c997 is the Ada 3D class, so the fault is on the graphics engine (vkd3d/DX12 submission), not compute or copy. It fired 12 times across ~85 minutes, each against a fresh game PID. The second GPU at PCI line at 22:45 is the driver reloading after a full PC restart. That matches what I was doing: relaunching repeatedly after the game crashed before reaching the main menu, both before and after the reboot.
I don't yet have -p err output from a crash on 7.2.0 or 6.18.42-LTS (my "always crashes" combo). I'll capture it next time and post it to the forum thread too. It'd be worth someone on a non-CachyOS distro grabbing the same output if they can reproduce.
linux-cachyos-nvidia-open, version-pinned to each kernel tested), CUDA UMD 13.3| Kernel | Proton | Result |
|---|---|---|
linux-cachyos 7.2.0-1 |
11.0-2 stock | Crashes (where this started, after a routine pacman -Syu) |
| 7.2.0-1 | proton-cachyos-11.0-20260703 | Crashes before main menu (worse than stock) |
| 7.2.0-1 | 10.x stock | Crashes |
linux-cachyos-lts 6.18.42-1 |
proton-cachyos-11.0-20260703 | Crashes, same signature |
| 6.18.42-1-lts | 10.x stock | Completed one Operation, degraded performance |
| 7.1.8-1 (kernel + headers + nvidia-open from pacman cache) | 11.0-1 stock (assumed, not recorded) | Stable, fresh Wine prefix, long session at Ultra |
| 7.1.8-1 | proton-cachyos-11.0-20260703 | Stable for ~2 weeks of sessions |
@JMarcosHP's openSUSE result at 7.1.8 (no crashes) matches this, so it looks version-specific rather than CachyOS-specific. Unconfirmed: a Reddit comment reports crashes on 7.1.9 (Omarchy), which would make the safe window narrower than "7.1.x good, 7.2.x bad".
From PROTON_LOG=1:
trace:seh:dispatch_exception code=c0000005 (EXCEPTION_ACCESS_VIOLATION) flags=0 addr=<see below>
Followed by a second mscoree/.NET process (presumably EAC) throwing code=6be (RPC_S_CALL_FAILED) and code=6ba (RPC_S_SERVER_UNAVAILABLE), which I read as it losing its RPC peer after the game dies.
| Build | Fault address |
|---|---|
| 7.2.0, Proton 11, original | 0x14271AB2C |
| 7.2.0, later session | 0x14215902E (identical across 3 crashes) |
| After game patch 14.2 | 0x14271AAEC (64 bytes from the original, likely the same function) |
Within one kernel/Proton/game build the address is identical across crashes while info[1] differs each time (0x0B, 0xFB, 0x23). Same instruction, different auxiliary data reads more like a race or use-after-free than a deterministic bug, but that's my interpretation without symbols.
Kernel logs (journalctl -k) were clean around these 7.2.0/LTS crashes: no Xid, no GPU reset.
On the previously-stable 7.1.8 + proton-cachyos combination: a freeze mid-session (FPS locked at 57, didn't recover), then a crash-loop before the main menu that survived a full reboot. Switching to Proton 11.0-2 later that night fixed it immediately. Next day I switched back to proton-cachyos to reproduce and it ran clean.
Two things changed around then, neither confirmed causal:
-p err also shows a kwin display-output-configuration failure at 22:28:20, right after the last Xid in the first boot.I want to be careful not to over-link this to the 7.2.0 crash. It presented differently (freeze, then loop), the 7.2.0 crashes had clean kernel logs, and I have no PROTON_LOG for this window (the log had grown past a million lines without rotation). It may be a separate failure mode, possibly display-topology related, rather than corroboration of the kernel-version issue.
nvidia-smi clocks and temps normalsystemd-coredump (consistent with an SEH exception inside Wine, not a raw SIGSEGV)client/reports/error.yaml never generatedkernel.yama.ptrace_scope: at default 1, so not the EAC/ptrace issuecompatdata/2183900PROTON_ENABLE_NTSYNC=0: no effect on 7.2.0 (doesn't rule out sync-primitive behaviour more broadly, just this toggle)ratbagctl scripting: removed, no effectA race or use-after-free in the game whose trigger probability is shifted by kernel timing (scheduler, ntsync/futex) and GPU load. 7.1.8 makes it rare but not impossible, which would fit both the two-week stable run and one bad night. I can't reproduce the 09-06 incident on demand, which is the main gap here.
I'll try to give some output using 7.2.2 and 7.1.8 from openSUSE.
I am on 7.2.2-1 on Cachy Standard and I am currently crashfree and this confuses me at the moment.
> Sep 07 21:46:38 tribble systemd[1]: Starting Daily Cleanup of Snapper Snapshots...
> Sep 07 21:46:38 tribble systemd[1]: Started Daily Cleanup of Snapper Snapshots.
> Sep 07 21:46:38 tribble systemd[1]: Starting DBus interface for snapper...
> Sep 07 21:46:38 tribble systemd[1]: Started DBus interface for snapper.
> Sep 07 21:46:38 tribble systemd-helper[150328]: Running cleanup for 'root'.
> Sep 07 21:46:38 tribble systemd-helper[150328]: Running number cleanup for 'root'.
> Sep 07 21:46:38 tribble systemd-helper[150328]: Running timeline cleanup for 'root'.
> Sep 07 21:46:38 tribble systemd-helper[150328]: Running empty-pre-post cleanup for 'root'.
> Sep 07 21:46:39 tribble limine-snapper-sync[150355]: Snapshot limit mismatch: 50 Snapper snapshots exceed configured MAX_SNAPSHOT_ENTRIES=8
> Sep 07 21:46:39 tribble limine-snapper-sync[150367]: Snapshot limit mismatch: 50 Snapper snapshots exceed configured MAX_SNAPSHOT_ENTRIES=8
> Sep 07 21:46:39 tribble limine-snapper-sync[150355]: To remove this warning, increase MAX_SNAPSHOT_ENTRIES or lower the Snapper limit.
> Sep 07 21:46:39 tribble systemd[1]: snapper-cleanup.service: Deactivated successfully.
> Sep 07 21:46:45 tribble discord[142888]: 21:46:45.491 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:46:45 tribble discord[142888]: 21:46:45.521 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:46:55 tribble discord[142888]: 21:46:55.116 › [Connection(default)] updateVideoQuality: {"remoteSinkWantsMaxFramerate":30}
> Sep 07 21:46:59 tribble discord[142888]: 21:46:59.242 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:46:59 tribble discord[142888]: 21:46:59.271 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:47:12 tribble discord[142888]: 21:47:12.992 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:47:13 tribble discord[142888]: 21:47:13.025 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:47:26 tribble discord[142888]: 21:47:26.741 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:47:26 tribble discord[142888]: 21:47:26.775 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:47:39 tribble systemd[1]: snapperd.service: Deactivated successfully.
> Sep 07 21:47:40 tribble discord[142888]: 21:47:40.492 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:47:40 tribble discord[142888]: 21:47:40.521 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:47:46 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:47:46 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:47:46 tribble systemd[1332]: Started Alacritty - Terminal.
> Sep 07 21:47:48 tribble discord[142888]: 21:47:48.151 › [RunningGameStore] Running Games Changed [object Object]
> Sep 07 21:47:48 tribble discord[142888]: 21:47:48.155 › [RunningGameStore] Running Non-Games Changed [object Object]
> Sep 07 21:47:48 tribble discord[142888]: 21:47:48.157 › [OverlayBridgeStore] updateIntendedOverlayPIDs [object Object]
> Sep 07 21:47:48 tribble discord[142888]: 21:47:48.157 › [OverlayBridgeStore] updateIntendedOverlayPIDs [object Object]
> Sep 07 21:47:48 tribble discord[142888]: 21:47:48.157 › [OverlayBridgeStore] updateIntendedOverlayPIDs: Removing all. [object Object] [object Object]
> Sep 07 21:47:48 tribble discord[142888]: 21:47:48.158 › [Clips] decider: handleRunningGamesChange visibleGame=Warhammer 40,000: Space Marine II newPrimaryKey=s:/steamapps/common/space marine 2/client_pc/root/bin/pc/warhammer 40000 s>
> Sep 07 21:47:48 tribble discord[142888]: 21:47:48.158 › [Clips] decider: handleRunningGamesChange — same primary, cancelling pending end
> Sep 07 21:47:54 tribble discord[142888]: 21:47:54.242 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:47:54 tribble discord[142888]: 21:47:54.271 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:48:00 tribble discord[142888]: 21:48:00.203 › [ConnectionEventFramerateReducer] BaseConnection.userSpeakingChange: Reduced framerate after 15000 ms.
> Sep 07 21:48:00 tribble discord[142888]: 21:48:00.203 › [Connection(default)] updateVideoQuality: {"remoteSinkWantsMaxFramerate":20}
> Sep 07 21:48:03 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:48:03 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:48:07 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:48:07 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:48:07 tribble discord[142888]: 21:48:07.992 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:48:08 tribble discord[142888]: 21:48:08.035 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:48:13 tribble discord[142888]: 21:48:13.166 › [RunningGameStore] Running Games Changed [object Object]
> Sep 07 21:48:13 tribble discord[142888]: 21:48:13.171 › [RunningGameStore] Running Non-Games Changed [object Object]
> Sep 07 21:48:13 tribble discord[142888]: 21:48:13.172 › [OverlayBridgeStore] updateIntendedOverlayPIDs [object Object]
> Sep 07 21:48:13 tribble discord[142888]: 21:48:13.172 › [OverlayBridgeStore] updateIntendedOverlayPIDs [object Object]
> Sep 07 21:48:13 tribble discord[142888]: 21:48:13.172 › [OverlayBridgeStore] updateIntendedOverlayPIDs: Removing all. [object Object] [object Object]
> Sep 07 21:48:13 tribble discord[142888]: 21:48:13.173 › [Clips] decider: handleRunningGamesChange visibleGame=Warhammer 40,000: Space Marine II newPrimaryKey=s:/steamapps/common/space marine 2/client_pc/root/bin/pc/warhammer 40000 s>
> Sep 07 21:48:13 tribble discord[142888]: 21:48:13.173 › [Clips] decider: handleRunningGamesChange — same primary, cancelling pending end
> Sep 07 21:48:15 tribble discord[142888]: 21:48:15.460 › [Connection(default)] updateVideoQuality: {"remoteSinkWantsMaxFramerate":30}
> Sep 07 21:48:16 tribble spectacle[74270]: QQmlComponent: Cannot create a component in an invalid context
> Sep 07 21:48:16 tribble spectacle[74270]: QQmlComponent: Cannot create a component in an invalid context
> Sep 07 21:48:22 tribble discord[142888]: 21:48:22.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:48:22 tribble discord[142888]: 21:48:22.145 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:48:24 tribble steam[77600]: pid 143862 != 143861, skipping destruction (fork without exec?)
> Sep 07 21:48:24 tribble steam[77600]: Game Recording - game stopped [gameid=2183900]
> Sep 07 21:48:24 tribble steam[77600]: Removing process 144013 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143996 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143962 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143955 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143953 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143943 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143898 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143884 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143879 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143869 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143866 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143864 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143861 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143860 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143859 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143854 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143759 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143758 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143757 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143752 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143745 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143744 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143742 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143740 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143737 for gameID 2183900
> Sep 07 21:48:25 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:48:25 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.148 › [RunningGameStore] Running Games Changed [object Object]
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.151 › [RunningGameStore] Running Non-Games Changed [object Object]
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.152 › [OverlayBridgeStore] updateIntendedOverlayPIDs [object Object]
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.152 › [OverlayBridgeStore] updateIntendedOverlayPIDs [object Object]
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.152 › [OverlayBridgeStore] updateIntendedOverlayPIDs: Removing all. [object Object] [object Object]
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.152 › [Clips] decider: handleRunningGamesChange visibleGame=null newPrimaryKey=null currentSessionGameKey=s:/steamapps/common/space marine 2/client_pc/root/bin/pc/warhammer 40000 spa>
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.152 › [Clips] decider: handleRunningGamesChange — visible game became null, finalizing session immediately
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.152 › [Clips] decider: processClipCandidates — sessionId=3f0aecee-9065-44b7-a936-ab6b40f0c264 candidates=0 staleCandidates=0 autoStashEnabled=false
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.153 › [Clips] ranked clips: [object Object]
> Sep 07 21:48:35 tribble steam[77600]: reaping pid: 144543 -- gameoverlayui
> Sep 07 21:48:36 tribble discord[142888]: 21:48:36.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:48:36 tribble discord[142888]: 21:48:36.146 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:48:41 tribble discord[142888]: 21:48:41.116 › [ConnectionEventFramerateReducer] BaseConnection.userSpeakingChange: Reduced framerate after 15000 ms.
> Sep 07 21:48:41 tribble discord[142888]: 21:48:41.116 › [Connection(default)] updateVideoQuality: {"remoteSinkWantsMaxFramerate":20}
> Sep 07 21:48:44 tribble discord[142888]: 21:48:44.116 › [WindowVisibilityVideoManager] Incoming video enabled changed, incomingVideoEnabled = false
> Sep 07 21:48:50 tribble discord[142888]: 21:48:50.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:48:50 tribble discord[142888]: 21:48:50.145 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:49:03 tribble discord[142888]: 21:49:03.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:49:03 tribble discord[142888]: 21:49:03.146 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:49:17 tribble discord[142888]: 21:49:17.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:49:17 tribble discord[142888]: 21:49:17.145 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:49:31 tribble discord[142888]: 21:49:31.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:49:31 tribble discord[142888]: 21:49:31.143 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:49:45 tribble discord[142888]: 21:49:45.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:49:45 tribble discord[142888]: 21:49:45.145 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:49:58 tribble discord[142888]: 21:49:58.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:49:58 tribble discord[142888]: 21:49:58.144 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:50:12 tribble discord[142888]: 21:50:12.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:50:12 tribble discord[142888]: 21:50:12.143 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:50:26 tribble discord[142888]: 21:50:26.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:50:26 tribble discord[142888]: 21:50:26.144 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:50:40 tribble discord[142888]: 21:50:40.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:50:40 tribble discord[142888]: 21:50:40.144 › [RTCControlSocket(default)] Heartbeat ACK received
Tested linux-cachyos-bore kernel 7.2.3 and still crashed. Wanted to test out since cachyos readme suggests the bore kernel for gaming.
journalctl -b -p err for this boot is clean: no Xid, no kernel-level fault of any kind.
Sep 07 23:36:59 cachyos kernel: virt/tdx: TDX not supported by the host platform
Sep 07 23:37:05 Atlas wpa_supplicant[966]: wlan0: nl80211: kernel reports: multicast RX registrations are not supported
Sep 07 23:37:07 Atlas libvirtd[971]: cannot open directory '/var/lib/libvirt/images/pool': No such file or directory
Sep 07 23:37:18 Atlas org_kde_powerdevil[1675]: [ 1675][ 1.627494] Time since library initialized: 1.627494 seconds
PROTON_LOG=1 shows the same signature as before. This time I have the full exception and backtrace:
2044.270:01a0:01b4:trace:seh:dispatch_exception code=c0000005 (EXCEPTION_ACCESS_VIOLATION) flags=0 addr=0000000142158FEE
2044.270:01a0:01b4:trace:seh:dispatch_exception info[0]=0000000000000000
2044.270:01a0:01b4:trace:seh:dispatch_exception info[1]=000000000000000B
2044.270:01a0:01b4:trace:seh:dispatch_exception rip=0000000142158fee rsp=00000000197bfc48 rbp=0000000142159040 eflags=00010246
2044.270:01a0:01b4:trace:seh:dispatch_exception rax=0000000000000000 rbx=000000010d44ebc0 rcx=0000000000000003 rdx=0000000000000000
2044.270:01a0:01b4:trace:seh:dispatch_exception rsi=0000000340e68640 rdi=0000000340e68600 r8=000000010d44eba0 r9=00006ffffffa77e0
2044.270:01a0:01b4:trace:seh:dispatch_exception r10=00006ffffc530000 r11=000000002f451c70 r12=0000000000000000 r13=00000000081a4000
2044.270:01a0:01b4:trace:seh:dispatch_exception r14=000000017eb08fd8 r15=00000000197bfce0 mxcsr=00001f80 cs=0033 ss=002b
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 0000000142158FEE: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002158FEE.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 0000000142175F8E: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002175F8E.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 00000001421590AA: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000021590AA.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 0000000142658DCD: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002658DCD.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 00000001426AC595: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000026AC595.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 00000001426DB7A9: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000026DB7A9.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 00000001426DA4F4: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000026DA4F4.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 0000000142726CF9: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002726CF9.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 00006FFFFFEC1649: L"kernel32.dll" + 0000000000011649.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 00006FFFFFF40E0F: L"ntdll.dll" + 0000000000010E0F.
(Claude)
What this shows:
info[0]=0, info[1]=0xB: a read from address 0xB, i.e. a null pointer dereference at a small field offset. rax, rdx and r12 are all zero at the fault. The earlier crashes had info[1] of 0x0B, 0xFB and 0x23, so every capture is a near-null read on the same instruction, never a random heap address. That points at a missing null check on something that comes back empty under certain timing (a lookup, a not-yet-ready resource, an already-released handle), rather than heap corruption.0x14215902E), so the same function for all practical purposes. 0x142158FEE is a small leaf helper with no stack frame, called from 0x142175F8E.Retail.exe, from the crash down to the kernel32/ntdll thread start. No EAC, Proton, or Nvidia Streamline module (DLSS, DLSS-G, Reflex, DeepDVC) is on it. It's a worker thread the engine created itself (01b4, a low thread ID created right after the main thread), dying about 11 minutes into the session.Versions for this run: stock Proton 11.0-2 (proton-11.0-2c+ per DXVK-NVAPI), DXVK v2.7.1-498-ga6764047e587178, vkd3d-proton build 212991fc2c266bc.
So the crash has now reproduced across:
Only 7.1.8 has been consistently stable for me, with the one exception. Given this is a null read in CPU code, that Xid 13 incident now looks like a separate failure mode rather than the same bug, since a GPU command-buffer fault wouldn't present this way.
My read is that the fix probably has to come from Saber: the fault is a null pointer de-reference on a worker thread in their own binary, and 7.1.8 most likely just shifts timing so the race is rarely lost, rather than fixing anything. But whatever changed between 7.1.8 and 7.2.0 is still worth identifying, since it may expose the same kind of latent race in other timing-sensitive games.
(Claude)
How do you get these logs? I tried launching Steam from the command line and then playing Space Marine, but after the crash, the output doesn't contain any relevant logs.
Same with journal.
I tried with 7.2.2, it crashes after 30 mins of gameplay.
Specs:
Operating System: openSUSE Tumbleweed 20260902
KDE Plasma Version: 6.7.4
KDE Frameworks Version: 6.29.0
Qt Version: 6.11.2
Kernel Version: 7.2.2-1-default (64-bit)
Graphics Platform: Wayland
Processors: 16 × AMD Ryzen 7 5700X 8-Core Processor
Memory: 32 GiB of RAM (31.3 GiB usable)
Graphics Processor: AMD Radeon RX 7600
Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-5579166996
Those are proton logs. You need to add PROTON_LOG=1 to your launch options and a log file will be generated in your home directory named steam-2183900.log
I seem to encounter very similar, almost identical issues to the latest posters, also on kernel 7.2.x - I add comment here - not to bloat or clobber the thread - but in case my logs provide any additional details not collected yet :)
I checked journalctl, but there's no entries at all. Which seems to indicate it's not a kernel level crash, but rather a user/game-space crash.
report_2026_09_05_23_05_33_pid412.tar.gz - Contains crashdump and error.yaml from steam appdata
Distro: EndeavourOS / Arch
Kernel: 7.2.3-arch1-2
GPU: NVIDIA RTX 3070
Driver: 610.57.04
Session: Hyprland / Wayland
Game: Space Marine 2, Patch 14.2
Proton tested:
Behaviour:
Crash:
EXCEPTION_ACCESS_VIOLATION
RIP = 0x142158FEE
Proton log:
code=c0000005
addr=0000000142158FEE
read from near-null address
Post-crash RPC_S_SERVER_UNAVAILABLE occurs ~18 seconds AFTER the crash,
so does not appear causal.
Got my crashlog here.
Distro: CachyOS
Kernel: 7.2.3-1 linux-cachyos
GPU: AMD 7900XTX
Session: Wayland
Game: Space Marine 2, Patch 14.2
My log from 7.2.2 after 1hr playing siege normal difficulty and the first sector on hard, using proton-cachyos latest on openSUSE Tumbleweed.
Command line options:
ENABLE_VKBASALT=1 PROTON_FSR4_RDNA3_UPGRADE=1 PROTON_DISCORD_BRIDGE=1 LOW_LATENCY_LAYER=1 PROTON_LOG=1 gamemoderun %command%
Error:
EXCEPTION_ACCESS_VIOLATION
5839.463:01b0:01c4:warn:seh:dispatch_exception backtrace: --- Exception 0xc0000005.
5839.464:01b0:01c4:trace:seh:dispatch_exception code=c0000005 (EXCEPTION_ACCESS_VIOLATION) flags=0 addr=0000000142158FEE
5839.464:01b0:01c4:trace:seh:dispatch_exception info[0]=0000000000000000
5839.464:01b0:01c4:trace:seh:dispatch_exception info[1]=000000000000006B
5839.464:01b0:01c4:trace:seh:dispatch_exception rip=0000000142158fee rsp=00000000198bfc48 rbp=0000000142159040 eflags=00010246
5839.464:01b0:01c4:trace:seh:dispatch_exception rax=0000000000000000 rbx=00000001543c91c0 rcx=0000000000000003 rdx=000000000000000c
5839.464:01b0:01c4:trace:seh:dispatch_exception rsi=000000015bd6f440 rdi=000000015bd6f400 r8=00000001543c91a0 r9=0000000000000013
5839.464:01b0:01c4:trace:seh:dispatch_exception r10=00006ffffc180000 r11=0000000032d91c70 r12=0000000000000000 r13=00000000082a4100
5839.464:01b0:01c4:trace:seh:dispatch_exception r14=000000011cd017f8 r15=00000000198bfce0 mxcsr=00001f80 cs=0033 ss=002b
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 0000000142158FEE: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002158FEE.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 142158fee rva 2158fee rsp 198bfc48
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 0000000142175F8E: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002175F8E.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 142175f8e rva 2175f8e rsp 198bfc50
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 2175e92-2175fa7
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143E97020 flags 4 prolog 0x11 bytes function 0000000142175E92-0000000142175FA7
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x11: movq %rdi,0x88(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0xd: movq %rsi,0x80(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x4: movq %rbp,0x78(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info chained to function 0000000142175E8B-0000000142175E92
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143E9700C flags 4 prolog 0x4 bytes function 0000000142175E8B-0000000142175E92
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x4: movq %rbx,0x70(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info chained to function 0000000142175E80-0000000142175E8B
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143E97000 flags 0 prolog 0xb bytes function 0000000142175E80-0000000142175E8B
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0xb: subq $0x58,%rsp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x7: pushq %r15
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x5: pushq %r12
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 00000001421590AA: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000021590AA.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 1421590aa rva 21590aa rsp 198bfcc0
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 2159040-21590fe
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143E96370 flags 0 prolog 0x10 bytes function 0000000142159040-00000001421590FE
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x10: movq %rsi,0x68(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x10: movq %rbx,0x60(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x10: subq $0x50,%rsp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0xc: pushq %rdi
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 0000000142658DCD: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002658DCD.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 142658dcd rva 2658dcd rsp 198bfd20
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 2658d50-2658e93
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143EC395C flags 0 prolog 0x19 bytes function 0000000142658D50-0000000142658E93
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x19: movq %rdi,0x78(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x19: movq %rsi,0x70(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x19: movq %rbp,0x68(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x19: movq %rbx,0x60(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x19: subq $0x50,%rsp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x15: pushq %r14
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 00000001426AC595: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000026AC595.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 1426ac595 rva 26ac595 rsp 198bfd80
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 26ac41b-26ac66d
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143ECA5E4 flags 4 prolog 0x4 bytes function 00000001426AC41B-00000001426AC66D
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x4: movq %r15,0xb0(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info chained to function 00000001426AC400-00000001426AC41B
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143ECA5C0 flags 4 prolog 0x1b bytes function 00000001426AC400-00000001426AC41B
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x1b: movq %r14,0xb8(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x13: movq %r13,0xc0(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0xc: movq %r12,0xc8(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x8: movq %rdi,0xd0(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x4: movq %rsi,0x100(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info chained to function 00000001426AC3F0-00000001426AC400
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143D26E94 flags 0 prolog 0x10 bytes function 00000001426AC3F0-00000001426AC400
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x10: subq $0xd8,%rsp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x5: pushq %rbx
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x4: pushq %rbp
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 00000001426DB7A9: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000026DB7A9.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 1426db7a9 rva 26db7a9 rsp 198bfe70
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 26db780-26dbb7c
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143ECDDA8 flags 0 prolog 0x1a bytes function 00000001426DB780-00000001426DBB7C
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x1a: subq $0x58,%rsp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x16: pushq %r15
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x14: pushq %r14
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x12: pushq %r13
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x10: pushq %r12
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0xe: pushq %rdi
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0xd: pushq %rsi
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0xc: pushq %rbp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0xb: pushq %rbx
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 00000001426DA4F4: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000026DA4F4.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 1426da4f4 rva 26da4f4 rsp 198bff10
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 26da3e0-26da51a
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143ECDC34 flags 0 prolog 0xa bytes function 00000001426DA3E0-00000001426DA51A
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0xa: movq %rbx,0x38(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0xa: subq $0x20,%rsp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x6: pushq %rdi
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 0000000142726CF9: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002726CF9.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 142726cf9 rva 2726cf9 rsp 198bff40
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 2726cc0-2726d00
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143ED4050 flags 0 prolog 0x4 bytes function 0000000142726CC0-0000000142726D00
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x4: subq $0x38,%rsp
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 00006FFFFFEA1649: L"kernel32.dll" + 0000000000011649.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 6fffffe90000 rip 6fffffea1649 rva 11649 rsp 198bff80
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 11640-11650
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 00006FFFFFED9FE8 flags 0 prolog 0x4 bytes function 00006FFFFFEA1640-00006FFFFFEA1650
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x4: subq $0x28,%rsp
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 00006FFFFFF20E2F: L"ntdll.dll" + 0000000000010E2F.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 6ffffff10000 rip 6ffffff20e2f rva 10e2f rsp 198bffb0
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 10e18-10e30
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 00006FFFFFFD81FC flags 1 prolog 0x4 bytes function 00006FFFFFF20E18-00006FFFFFF20E30
5839.464:01b0:01c4:trace:unwind:dump_unwind_info 0x4: subq $0x28,%rsp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info handler 00006FFFFFF69420 data at 00006FFFFFFD8208
5839.464:01b0:01c4:trace:seh:call_seh_handlers calling handler 00006FFFFFF69420 (rec=00000000198BFA30, frame=198bffb0 context=00000000198BF540, dispatch=00000000198BECD0)
I hope this helps someone.
OS: NixOS 26.11 (Zokor)
KERNEL: 7.2.2
CPU: AMD Ryzen 7 7800X3D 8-Core
GPU: NVIDIA GeForce RTX 5070
GPU DRIVER: NVIDIA 595.91.07
RAM: 31 GB
I've tested Proton Experimental, Hotfix, 11, 10, and 9. There are two different behaviors:
Unexpected Error #1 in the launcher.Crash Dump Sending Utility window.I had no issues during the campaign. The problems only started when I switched to Operations/online mode.
Somehow, I came across this comment and decided to try it on my machine. I switched the kernel from 7.2.2 to 7.1.13 and switched to Proton 11.0-2.
It helped, and now I can play normally and enjoy the game without any issues.
At least, I haven't seen any crashes or other problems after two days of daily gameplay in both campaign and online modes, including long single-session play.
OS: CachyOS x86_64
KERNEL: 7.2.5-1-cachyos
CPU: AMD Ryzen 7 9800X3D 8-Core
GPU: NVIDIA GeForce RTX 5090
RAM: 96 GB
Proton GE, Proton Hotfix, 11, 10 and 9 tested. All have the crash occur.
I am still experiencing the same crash on Linux kernel 7.2.5-1-cachyos. Mid-session will just fail. Does not occur on my LTS 6.18 kernel (as far as I can tell)
the issue is still happening with the most recent kernel releases, right? I've been trying to bisect to find what change made this issue manifest. The problem is that on my end it can take up to 3 hours for the issue to pop up (though it's usually less).
Here's a kernel build for for arch based systems, hopefully it should work on any x64 system. Note that this is just the kernel and not the headers, so not fit for people that need out of tree modules:
https://we.tl/t-H3Gz3PJL6VtkyL6p this link should be available for 3 days
Posting a data point that looks like a different failure from the one this thread is tracking, in case it's useful to whoever is bisecting — happy to move this to a separate issue if maintainers prefer.
The reports here are EXCEPTION_ACCESS_VIOLATION, mid-mission, with no kernel-level fault (several people explicitly note journalctl is clean), and improved by the 6.18 LTS kernel. Mine is the opposite on all three counts: a GPU-level fault, at startup, which still reproduces on 6.18 LTS.
Crash on the start screen or within ~1s of the main menu rendering. Gameplay is never reached. 100% reproducible, every launch.
Every crash produces an identical kernel fault:
NVRM: Xid (PCI:0000:01:00): 13, pid=<varies>, name=Warhammer 40000, Graphics Exception:
channel 0x0000000b, Class 0000c997, Offset 00000000, Data 00000000
Xid 13 (Graphics Exception — illegal instruction/method), not Xid 31 (page fault). Class 0000c997 is the Ada compute class. Offset and Data are zero on every occurrence.
vkd3d-proton then reports device loss:
err:vkd3d-proton:vkd3d_wait_for_gpu_timeline_semaphore: Failed to wait for Vulkan timeline semaphore, vr -4.
warn:vkd3d-proton:d3d12_device_mark_as_removed: Device ... is lost (reason 0x887a0005, "VK_ERROR_DEVICE_LOST").
err:vkd3d-proton:dxgi_vk_swap_chain_ensure_unsignaled_swapchain_fence: Failed to wait for fences, vr -4
err:vkd3d-proton:dxgi_vk_swap_chain_present_signal_blit_semaphore: Failed to submit present discard, vr = -4.
nvidia-open-dkms 610.57.04| Variable | Tested | Result |
|---|---|---|
| Kernel | 7.2.5, 7.2.3, 6.18.49 LTS | identical |
| Proton | 9.0-4f, Experimental experimental-11.0 (vkd3d-proton 3.1.0) |
identical |
| NvAPI/DLSS | PROTON_DISABLE_NVAPI=1 |
identical |
| ReBAR/HVV upload heaps | VKD3D_CONFIG=no_upload_hvv |
identical |
| Shader/pipeline cache | cleared | identical |
| Game files | Steam verify | nothing repaired |
| Steam overlay | disabled | identical |
For the NvAPI test I confirmed Proton removed nvapi64.dll from the prefix and that nvapi64 and LaunchCubinShader appear 0 times in the log — worth stating because the game does otherwise drive a CUDA cubin path (NvAPI_D3D12_CreateCubinComputeShaderExV2 / LaunchCubinShader, with several Invalid pointer returns from DXVK-NVAPI) that looked like a promising culprit. Disabling it entirely changes nothing.
VKD3D_CONFIG=fault (VK_EXT_device_fault) returns an empty report:
err:vkd3d-proton:d3d12_device_report_fault: DEVICE_LOST received, reporting fault.
err:vkd3d-proton:d3d12_device_report_fault: Desc:
No fault address, no vendor info — so no page fault, and none of vkd3d's use-after-free / out-of-bounds diagnostics fire.
VKD3D_CONFIG=log_memory_budget at the moment of the crash:
Memory heap #0 [DEVICE_LOCAL], size 16376 MiB, budget: 15202 MiB, usage: 2821 MiB
2.8 GB of a 15 GB budget — not memory pressure, despite the game polling NtGdiDdDDIQueryStatistics (a wine stub) every frame right up to the fault.
Taken together: an illegal instruction reaching the Ada compute engine, with no bad address and no memory pressure.
The only variable I have not been able to test is the NVIDIA driver branch — 610.43.03 and 610.57.04 are in-branch neighbours, so every driver I've run shares a shader compiler. Given the fault is invariant across three kernels and two vkd3d generations, that's where I'd look next, but I'm not in a position to run a cross-branch test on this machine.
Full Proton log available on request.
@Rombond yours is a different issue, but all issues for a given game go in the same thread so it should remain here anyway. My testing for the other crash mentioned here has been on my amd desktop, but as I also have a nvidia laptop with a 4060, I tried there but the game was working there.
This was with nvidia 615.71.09, so it would be a good idea if you tried upgrading your drivers first and see if that works for you.
Around 2 hours with my kernel build and no crash yet. If anyone downloaded that build and gave it a spin I'd like to know if it has crashed for you, and if not, how long you played the game
the issue is still happening with the most recent kernel releases, right? I've been trying to bisect to find what change made this issue manifest. The problem is that on my end it can take up to 3 hours for the issue to pop up (though it's usually less).
Here's a kernel build for for arch based systems, hopefully it should work on any x64 system. Note that this is just the kernel and not the headers, so not fit for people that need out of tree modules:
https://we.tl/t-H3Gz3PJL6VtkyL6p this link should be available for 3 days
I installed 7.1.13 from Koji on a Fedora 44 KDE system, after 3 hours of gameplay I got 0 crashes. So something in the Kernel is helping to mitigate that EXCEPTION_ACCESS_VIOLATION, have you figured out with the bisect what the change is?
@@JMarcosHP The bisect isn't finished, I don't know how it is for others, but if I'm unlucky it can take over 2 hours to crash, this of course makes the bisect harder as it takes longer to know whether a commit is good or if it just hasn't crashed yet.
I have another build for now, if others run the game with it and report back it can help speed things up.
https://we.tl/t-r9athW2qxk1BTicP
Retail.exe+0x2158FEE (resFILE_LOADER, rcx = 3)TL;DR: This is a game bug that Wine triggers far more often than Windows does.
RtlWaitOnAddress() can leave a stale thread alert behind, and it makes that wait return early. Most of these come from the game's tcmalloc, whose spinlock back-off calls WaitOnAddress() with a timeout that can round down to 0 ms.A two-part ntdll fix (below) removes the stale alerts. With it I've played 2 h 40 min without a crash, against 8 crashes in about 7 h 20 min before on the same setup.
Setup:
The exe loads at its preferred base 0x140000000, so offsets below are relative to that.
+0x205AC90 builds a vector of 24-byte records on its stack, each with status 3 (pending). For each record it registers a completion callback capturing [&records, index]; the lambda's ops table is at +0x37C5790. It then submits the batch (+0x216DA90) and waits on the returned future, with no loop:EnterCriticalSection(&f->cs);
if (f->state != 2 && f->state != 3)
SleepConditionVariableCS(&f->cv, &f->cs, INFINITE); /* call at +0x205AF82 */
LeaveCriticalSection(&f->cs);
The SleepConditionVariableCS docs say this needs a loop, with no exception for INFINITE: "Condition variables are subject to spurious wakeups (those not associated with an explicit wake) … you should recheck a predicate (typically in a while loop) after a sleep operation returns."resFILE_LOADER (+0x2175E80). It sets the state and calls WakeAllConditionVariable(), then runs the callbacks while still holding the critical section. So a real wake can't let the waiter leave before the callbacks finish; only a spurious wakeup can.+0x2158FD0) does records.data[index].status = 4 or 5 through the dangling &records. records.data is whatever now occupies that stack slot. That was 3 in my dumps and the ones posted here, so cmp dword [rcx+rdx*8+8] faults at 0xB / 0x3B / 0x6B (index 0 / 2 / 4). When the slot happens to hold a valid pointer, you get silent memory corruption instead.RtlWakeAddressSingle() / RtlWakeAddressAll() take a waiter off the queue under the queue spinlock, but only alert it after dropping the lock.RtlWaitOnAddress() returns STATUS_TIMEOUT and the alert stays pending on the thread. The thread's next NtWaitForAlertByThreadId() then returns immediately. That can be an unrelated SleepConditionVariableCS(INFINITE), like the one above.libtcmalloc_minimal.dll's spinlock back-off (gperftools-style SpinLockDelay) calls WaitOnAddress(lock, &locked, 4, ms) with a random delay converted to whole milliseconds, so short delays become 0 ms. It releases the lock with WakeByAddressSingle().+0x205AC90 allocates (growing the record vector) right before its wait.WaitOnAddress docs list "A previous wake on the same address was abandoned" as a cause of early returns. In Wine the leftover alert belongs to the thread, so an abandoned wake on tcmalloc's lock ends a wait on an unrelated condition variable.WakeByAddressSingle wakes "the first thread to wait", and "other waiting threads continue to wait". Handing that wake to a thread that is already timing out loses it for the thread that is actually waiting.Instrumented ntdll, in-game. The build logs whenever a waiter is dequeued as its wait times out. It logged over 2,000 of these in a 44-minute session. The 22 with backtraces all had timeout 0, all came from libtcmalloc_minimal.dll+0x178E, and all were on the game's allocating threads.
Reproducer (mingw source at the end of this comment). 8 workers each take a tcmalloc-style spinlock and then do the game's unlooped future wait.
| 15 s run on Proton Experimental 11.0-20260924 | Future waits | Returned while still pending |
|---|---|---|
| Stock | 526,409 | 56,049 |
| With the fix below | 527,657 | 0 |
Playing, same machine and settings.
| Build | Play time | Crashes |
|---|---|---|
| Stock Experimental 20260924 | about 7 h 20 min over 14 sessions | 8 |
| With the fix (same kernel 7.2.7, same game build) | 2 h 40 min | 0 |
The patched time includes a 1 h 56 min session; my longest session before that was 69 minutes, and it ended in a crash. The instrumented build logged no stale alerts left in the game.
Two small changes to RtlWaitOnAddress():
The patch is against ValveSoftware/wine experimental_11.0 (adea6cb) and also applies to upstream master. I also have a conformance test for ntdll/tests/sync.c that checks no thread alert is left pending after short waits race with wakes. It fails on current Proton Experimental and passes with the fix.
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 18e61e4..13d30c3 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -881,6 +881,7 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
{
struct futex_queue *queue = get_futex_queue( addr );
struct futex_entry entry;
+ BOOL queued = FALSE;
NTSTATUS ret;
TRACE("addr %p cmp %p size %#Ix timeout %s\n", addr, cmp, size, debugstr_timeout( timeout ));
@@ -888,6 +889,11 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
if (size != 1 && size != 2 && size != 4 && size != 8)
return STATUS_INVALID_PARAMETER;
+ /* Don't queue a zero-timeout wait. RtlWakeAddress*() could pick us and alert us only after we have
+ * returned, which would both steal the wake from a real waiter and end this thread's next wait early. */
+ if (timeout && !timeout->QuadPart)
+ return compare_addr( addr, cmp, size ) ? STATUS_TIMEOUT : STATUS_SUCCESS;
+
entry.addr = addr;
entry.tid = GetCurrentThreadId();
@@ -913,11 +919,16 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
if (entry.addr)
{
spin_lock( &queue->lock );
- if (entry.addr)
+ if ((queued = entry.addr != NULL))
list_remove( &entry.entry );
spin_unlock( &queue->lock );
}
+ /* If we were dequeued as our wait timed out, the waker alerts us right after releasing the queue lock.
+ * Take that alert and report the wake; otherwise it would end this thread's next wait early. */
+ if (!queued && ret == STATUS_TIMEOUT)
+ ret = NtWaitForAlertByThreadId( NULL, NULL );
+
TRACE("returning %#lx\n", ret);
if (ret == STATUS_ALERTED) ret = STATUS_SUCCESS;
I don't know which kernel change matters; nothing in this path depends on it directly. How often a stale alert lands on the thread that is about to do this wait depends on tcmalloc lock contention and on thread timing, so a scheduling change in 7.2 could plausibly raise the rate. The kernel isn't doing anything wrong. The reports here of crashes on 6.18 LTS fit this: older kernels make it rarer, not impossible.
The real fix is on Saber's side: make the wait a while loop.
x86_64-w64-mingw32-gcc -O2 -D__USE_MINGW_ANSI_STDIO=1 -o stale_wake.exe stale_wake.c -lsynchronization)/* Reproducer for spurious SleepConditionVariableCS() wakeups caused by stale thread alerts.
*
* Each worker alternates between:
* 1. a short timed wait on a shared "noise" condition variable that a pinger thread keeps waking, so that
* timeouts race with RtlWakeAddressAll() dequeuing the waiter; and
* 2. the Space Marine 2 engine's future pattern: `if (!done) SleepConditionVariableCS(INFINITE)`, without a
* predicate loop, completed by a dedicated completer thread.
* A return from (2) while the future is still pending is a spurious wakeup; in the game that is where the
* waiting function returns and the loader's callback later writes into its dead stack frame.
*
* Noise modes: "timed" = (1) above; "poll" = tcmalloc-style spinlock that polls with WaitOnAddress(..., 0) and
* releases with WakeByAddressSingle(), taken by allocator threads and by each worker right before its future wait
* (as in the game); "both" (default).
*
* Usage: stale_wake.exe [seconds] [workers] [timed|poll|both]
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct future
{
CRITICAL_SECTION cs;
CONDITION_VARIABLE cv;
volatile LONG state; /* 0 pending, 2 done */
};
struct worker
{
struct future f;
HANDLE go; /* auto-reset event: worker -> completer */
LONG64 futures, spurious;
DWORD seed;
};
static CRITICAL_SECTION noise_cs;
static CONDITION_VARIABLE noise_cv;
static volatile LONG stop, stop_completers;
static volatile LONG alloc_lock;
static BOOL use_timed = TRUE, use_poll = TRUE;
/* tcmalloc-style spinlock: poll with a zero timeout while contended. */
static void alloc_lock_acquire(void)
{
LONG locked = 1;
while (InterlockedCompareExchange( &alloc_lock, 1, 0 ))
WaitOnAddress( &alloc_lock, &locked, sizeof(locked), 0 );
}
static void alloc_lock_release(void)
{
InterlockedExchange( &alloc_lock, 0 );
WakeByAddressSingle( (void *)&alloc_lock );
}
static void fake_alloc(void)
{
volatile int i;
alloc_lock_acquire();
for (i = 0; i < 50; i++) ;
alloc_lock_release();
}
static DWORD WINAPI allocator( void *arg )
{
while (!stop) fake_alloc();
return 0;
}
static DWORD next_rand( DWORD *seed )
{
*seed = *seed * 1103515245 + 12345;
return *seed >> 8;
}
static void spin_us( LARGE_INTEGER freq, DWORD us )
{
LARGE_INTEGER start, now;
QueryPerformanceCounter( &start );
do QueryPerformanceCounter( &now );
while ((now.QuadPart - start.QuadPart) * 1000000 / freq.QuadPart < us);
}
static DWORD WINAPI pinger( void *arg )
{
LARGE_INTEGER freq;
DWORD seed = 1;
QueryPerformanceFrequency( &freq );
while (!stop)
{
WakeAllConditionVariable( &noise_cv );
spin_us( freq, 200 + next_rand( &seed ) % 1600 );
}
return 0;
}
static DWORD WINAPI completer( void *arg )
{
struct worker *w = arg;
LARGE_INTEGER freq;
DWORD seed = w->seed ^ 0x5bd1e995;
QueryPerformanceFrequency( &freq );
for (;;)
{
WaitForSingleObject( w->go, INFINITE );
if (stop_completers) break;
spin_us( freq, 20 + next_rand( &seed ) % 400 );
EnterCriticalSection( &w->f.cs );
w->f.state = 2;
WakeAllConditionVariable( &w->f.cv );
LeaveCriticalSection( &w->f.cs );
}
return 0;
}
static DWORD WINAPI worker_thread( void *arg )
{
struct worker *w = arg;
while (!stop)
{
/* 1: timed wait racing with the pinger's wakes. */
if (use_timed)
{
EnterCriticalSection( &noise_cs );
SleepConditionVariableCS( &noise_cv, &noise_cs, 1 );
LeaveCriticalSection( &noise_cs );
}
/* 1b: allocate right before waiting, like the game growing its record vector. */
if (use_poll)
{
int i;
for (i = 0; i < 4; i++) fake_alloc();
}
/* 2: single-shot future wait, as in the game. */
w->f.state = 0;
SetEvent( w->go );
EnterCriticalSection( &w->f.cs );
if (w->f.state != 2)
{
SleepConditionVariableCS( &w->f.cv, &w->f.cs, INFINITE );
if (w->f.state != 2) w->spurious++;
}
/* resynchronise properly before the next round */
while (w->f.state != 2) SleepConditionVariableCS( &w->f.cv, &w->f.cs, INFINITE );
LeaveCriticalSection( &w->f.cs );
w->futures++;
}
return 0;
}
int main( int argc, char **argv )
{
int seconds = argc > 1 ? atoi( argv[1] ) : 30, count = argc > 2 ? atoi( argv[2] ) : 8, i;
const char *mode = argc > 3 ? argv[3] : "both";
struct worker *workers = calloc( count, sizeof(*workers) );
HANDLE *threads = calloc( 2 * count + 1, sizeof(*threads) ), allocators[4] = {0};
if (!strcmp( mode, "timed" )) use_poll = FALSE;
else if (!strcmp( mode, "poll" )) use_timed = FALSE;
LONG64 futures = 0, spurious = 0;
InitializeCriticalSection( &noise_cs );
InitializeConditionVariable( &noise_cv );
for (i = 0; i < count; i++)
{
InitializeCriticalSection( &workers[i].f.cs );
InitializeConditionVariable( &workers[i].f.cv );
workers[i].go = CreateEventW( NULL, FALSE, FALSE, NULL );
workers[i].seed = 0x9e3779b9 * (i + 1);
threads[2 * i] = CreateThread( NULL, 0, completer, &workers[i], 0, NULL );
threads[2 * i + 1] = CreateThread( NULL, 0, worker_thread, &workers[i], 0, NULL );
}
threads[2 * count] = CreateThread( NULL, 0, pinger, NULL, 0, NULL );
if (use_poll)
for (i = 0; i < ARRAYSIZE(allocators); i++)
allocators[i] = CreateThread( NULL, 0, allocator, NULL, 0, NULL );
Sleep( seconds * 1000 );
stop = 1;
for (i = 0; i < count; i++) WaitForSingleObject( threads[2 * i + 1], INFINITE );
stop_completers = 1;
for (i = 0; i < count; i++)
{
SetEvent( workers[i].go );
WaitForSingleObject( threads[2 * i], INFINITE );
futures += workers[i].futures;
spurious += workers[i].spurious;
}
WaitForSingleObject( threads[2 * count], INFINITE );
for (i = 0; i < ARRAYSIZE(allocators); i++)
if (allocators[i]) WaitForSingleObject( allocators[i], INFINITE );
printf( "%s: %d s, %d workers: %lld future waits, %lld returned while still pending (spurious)\n",
mode, seconds, count, (long long)futures, (long long)spurious );
fflush( stdout );
return 0;
}
Have you already submitted the patch for Wine? @jegglest
@JMarcosHP not yet, I wanted to get this information out as quickly as I could. I’ll submit the patch to Wine later today.
Update: I've revised the ntdll fix after looking harder at the corner cases. Summary of what changed since my comment above:
RtlWakeAddress*() clear a waiter's entry address and then unlink the entry, which lives on the waiter's stack, all under the queue lock. A waiter that times out reads that address without the lock, so it can see it cleared while the waker is still unlinking, return, and reuse its stack; the waker then writes through stale next/prev pointers. The waiter now checks under the lock.WakeByAddressSingle is never lost) and takes the in-flight alert within a 1 ms grace period instead of waiting for it indefinitely. In the stress test the alert was consumed every time.diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 18e61e4..4ddf670 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -881,6 +881,8 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
{
struct futex_queue *queue = get_futex_queue( addr );
struct futex_entry entry;
+ LARGE_INTEGER deadline;
+ BOOL queued;
NTSTATUS ret;
TRACE("addr %p cmp %p size %#Ix timeout %s\n", addr, cmp, size, debugstr_timeout( timeout ));
@@ -888,6 +890,19 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
if (size != 1 && size != 2 && size != 4 && size != 8)
return STATUS_INVALID_PARAMETER;
+ /* Don't queue a zero-timeout wait. RtlWakeAddress*() could pick us and alert us only after we have
+ * returned, which would both steal the wake from a real waiter and end this thread's next wait early. */
+ if (timeout && !timeout->QuadPart)
+ return compare_addr( addr, cmp, size ) ? STATUS_TIMEOUT : STATUS_SUCCESS;
+
+ /* Use an absolute deadline, so that waiting again after a stale alert doesn't extend the wait. */
+ if (timeout && timeout->QuadPart < 0)
+ {
+ NtQuerySystemTime( &deadline );
+ deadline.QuadPart -= timeout->QuadPart;
+ timeout = &deadline;
+ }
+
entry.addr = addr;
entry.tid = GetCurrentThreadId();
@@ -907,15 +922,31 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
spin_unlock( &queue->lock );
- ret = NtWaitForAlertByThreadId( NULL, timeout );
-
- /* We may have already been removed by a call to RtlWakeAddressSingle() or RtlWakeAddressAll(). */
- if (entry.addr)
+ for (;;)
{
+ ret = NtWaitForAlertByThreadId( NULL, timeout );
+
+ /* RtlWakeAddressSingle() and RtlWakeAddressAll() may have removed us already. They still read the
+ * entry after clearing its address, so check under the lock: a waker that has released it is done
+ * with it. An alert received while we are still queued wasn't sent by a waker, since they dequeue us
+ * first: it was left pending by an earlier wait. Ignore it and keep waiting. */
spin_lock( &queue->lock );
- if (entry.addr)
+ if ((queued = entry.addr != NULL) && ret != STATUS_ALERTED)
list_remove( &entry.entry );
spin_unlock( &queue->lock );
+
+ if (!queued || ret != STATUS_ALERTED) break;
+ }
+
+ if (!queued && ret != STATUS_ALERTED)
+ {
+ /* A waker removed us as our wait ended, so we have been woken. It alerts us right after releasing the
+ * queue lock; take that alert now, or it would end this thread's next wait early. Don't wait for it
+ * indefinitely though, in case the waker was preempted in between. */
+ LARGE_INTEGER grace = {.QuadPart = -10000}; /* 1 ms */
+
+ NtWaitForAlertByThreadId( NULL, &grace );
+ ret = STATUS_SUCCESS;
}
TRACE("returning %#lx\n", ret);
Filed the Wine side upstream as https://bugs.winehq.org/show_bug.cgi?id=60397, with the analysis and the fix approach in prose. It's a bug report rather than a merge request because the prototype above was written with an LLM tool, which Wine's Clean Room Guidelines exclude from patches.
Filed the Wine side upstream as https://bugs.winehq.org/show_bug.cgi?id=60397, with the analysis and the fix approach in prose. It's a bug report rather than a merge request because the prototype above was written with an LLM tool, which Wine's Clean Room Guidelines exclude from patches.
Nice, thank you.
Let's wait a decade until Wine devs fix this. /s
Filed the Wine side upstream as https://bugs.winehq.org/show_bug.cgi?id=60397, with the analysis and the fix approach in prose. It's a bug report rather than a merge request because the prototype above was written with an LLM tool, which Wine's Clean Room Guidelines exclude from patches.
Thank you
The game is still crashing consistently
OS: Arch Linux
KERNEL: 7.2.7-arch1-1
CPU: AMD Ryzen 7 7800X3D 8-Core
GPU: AMD Radeon RX 6700 XT (radeonsi, navi22, ACO, DRM 3.64, 7.2.7-arch1-1)
GPU DRIVER: 4.6 Mesa 26.2.3-arch1.1
RAM: 32 GB
When the issues started
About 30 days ago there was an update to both the game and proton which broke EAC, making it impossible to launch the game at all, easy enough, simply downgrading to proton 9 or proton 11 worked, few days after that proton experimental got updated and we could launch the game without issues, however, regardless of the proton version used the game started crashing frequently, another report of the issue not from me is here (https://steamcommunity.com/app/2183900/discussions/0/589562254618265197/).
Description of the issue:
When playing operations or siege mode, no matter if in solo or with other people, the game will crash after 2 to 50 minutes of playing, disabling EAC and playing offline didn't fix this issue, the crash happens this way, you will get a pop-up with a crash report window that asks you to send or decline to send a report, however the window is blank and doesn't show why the game crashed, furthermore the game will keep working for a few more minutes after the crash window pop up until it eventually freezes and closes down.
Since then I've started recording proton logs for the game until crash, here's 3 of them, along with them there's some crash logs automatically generated by the game, however these are not always generated during a crash, unsure why.
report_2026_09_22_23_51_53_pid408.zip
Some repeated errors seems to be
err:service:device_notify_proc failed to get event, error 1726
dispatch_exception code=6ba (RPC_S_SERVER_UNAVAILABLE)
and
1376.639:0198:019c:warn:threadname:NtSetInformationThread Thread handle 0x6d0 renamed to L"Decals BSP rebuild thread"
1376.675:0198:0208:trace:seh:GetPerformanceInfo (000000001259FDF0, 104)
1376.685:0198:03a0:trace:seh:GetPerformanceInfo (00000000C7CAFDF0, 104)
warn: CreateDXGIFactory2: Ignoring flags
1376.700:0198:025c:warn:vkd3d-proton:d3d12_pipeline_state_init_graphics_create_info: DSV format is DXGI_FORMAT_UNKNOWN.
1376.745:0198:025c:warn:vkd3d-proton:vkd3d_view_map_create_view2: Intense view map pressure! Got 1024 views in hash map 00000000fa0e9920. This may lead to out-of-memory errors in the extreme case.
1376.746:0198:025c:warn:vkd3d-proton:vkd3d_view_map_create_view2: Intense view map pressure! Got 2048 views in hash map 00000000fa0e9920. This may lead to out-of-memory errors in the extreme case.
1376.746:0198:025c:warn:vkd3d-proton:vkd3d_view_map_create_view2: Intense view map pressure! Got 3072 views in hash map 00000000fa0e9920. This may lead to out-of-memory errors in the extreme case.
1376.748:0198:025c:warn:vkd3d-proton:vkd3d_view_map_create_view2: Intense view map pressure! Got 4096 views in hash map 00000000fa0e9920. This may lead to out-of-memory errors in the extreme case.
While the game internal crash report indicates
"memory info": " Title memory: 5498.8/11073.2 mb (0.0 free)\nGeomStreaming: 547.1/550.0 mb\n TexStreaming: 1836.4/6179.2 mb (0.0 mips drop)\nReserved memory: 1000.0, 0.0 temp [mb]",
I can't make sense whenever it's a proton, sm2 or EAC issue, thought the game seems to be running fine on windows, I hope this can be helpful in making sense on what is going on.
Small edit:
Just to be clear before September I used to play this game quite a lot at max difficulties even in siege which generated a very large a mount of enemies and never crashed, for over a year the game ran perfectly without issues.
Windows comparison, and the probe used for it
The Wine maintainer's reply on Wine bug 60397 was that an alert left pending when a wake races a timed-out wait is inherent to Win32 futexes and cannot be avoided. To check that, I ran two programs on Windows 11 and on stock Proton Experimental on the same machine (Windows in a QEMU/KVM VM with 4 logical processors):
| Windows 11 25H2 (26200.9457) | Proton Experimental 11.0-20260924 | |
|---|---|---|
Zero-timeout RtlWaitOnAddress() calls that timed out while a waker was dequeuing them, of 20,000 (RtlWakeAddressSingle / RtlWakeAddressAll) |
39 / 47 | 147 / 126 |
| … of those, alerts left pending on the thread | 0 / 0 | 18 / 20 |
| 100 ns wait on an unrelated address returning early afterwards | 0 (189 samples; a 100 ns wait costs a timer tick on Windows) | 22 / 27 of 20,000 |
Unlooped SleepConditionVariableCS(INFINITE) returning while the future was still pending, stale_wake.exe 15 8 poll (source in my first comment above) |
0 of 100,097 | 69,195 of 529,155 (13%) |
same, both / timed modes |
0 of 26,073 / 0 of 85,325 | 24,088 of 137,275 / 45 of 139,069 |
So on Windows the wake that races a timed-out wait is consumed, not left pending, and the unlooped condition-variable wait never returned early in 100,000 tries. That is the shape of Windows' implementation: the wait block carries a flag that the waker and a timing-out waiter exchange; a waiter that finds itself already claimed does a second, untimed NtWaitForAlertByThreadId() to take the wake, and a waker that finds the waiter already timed out doesn't alert it. Wine's waiter returns STATUS_TIMEOUT and leaves the alert for the thread's next wait.
The game still has to loop its wait (Saber ticket 12458). This only establishes that the early return it hits is Wine behaviour, not Windows behaviour.
Patch status. The ntdll patch is now v5 and follows Windows here: the dequeued waiter takes the in-flight alert with an untimed wait (no 1 ms grace period any more), and the "ignore alerts while still queued" part is gone, since Windows does return on any alert and nothing is left for it to catch. The use-after-return fix stays, in a form that keeps the unlocked fast path. With v5: the probe gives 0 pending alerts and 0 early returns, stale_wake 0 spurious wakeups in all three modes at unchanged throughput, and Wine's ntdll:sync suite with a test added for this passes 441/441 in three runs, where stock fails the new test with 23–245 pending alerts per case. The same test binary passes on Windows 11 (441 tests, 0 failures; kernel32:sync 0 failures too). WINE_STALE_ALERT_FIX=0 still gives the A/B build. The three patches are below.
raced_wake_probe.c — build with x86_64-w64-mingw32-gcc -O2 -D__USE_MINGW_ANSI_STDIO=1 -o raced_wake_probe.exe raced_wake_probe.c/* Probe for a stale thread alert after a RtlWaitOnAddress() wake races the end of a short wait.
*
* A waker thread loops RtlWakeAddressSingle()/RtlWakeAddressAll() on one address while the main thread does short
* waits on it (timeout 0, then 100 ns), so that wakes race with the waits timing out. After each wait the thread
* checks whether the wake left an alert pending on it:
* - "probe" pass: NtWaitForAlertByThreadId(NULL, 0) returns STATUS_ALERTED if an alert is pending (and takes it);
* - "early" pass: a 100 ns RtlWaitOnAddress() on an unrelated address must time out. Anything else is an early
* return: in the game, that is what ends the unlooped SleepConditionVariableCS(INFINITE) early.
* Same measurement as the proposed Wine test test_wait_on_address_raced_wake(), built to run on Windows and Wine.
*
* Usage: raced_wake_probe.exe [iterations per pass, default 20000] [seconds cap per pass, default 3]
*/
#include <windows.h>
#include <winternl.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000)
#endif
#ifndef STATUS_ALERTED
#define STATUS_ALERTED ((NTSTATUS)0x00000101)
#endif
#ifndef STATUS_TIMEOUT
#define STATUS_TIMEOUT ((NTSTATUS)0x00000102)
#endif
static NTSTATUS (NTAPI *pRtlWaitOnAddress)( const void *, const void *, SIZE_T, const LARGE_INTEGER * );
static void (NTAPI *pRtlWakeAddressSingle)( const void * );
static void (NTAPI *pRtlWakeAddressAll)( const void * );
static NTSTATUS (NTAPI *pNtWaitForAlertByThreadId)( const void *, const LARGE_INTEGER * );
static NTSTATUS (NTAPI *pRtlGetVersion)( RTL_OSVERSIONINFOW * );
static const char * (CDECL *pwine_get_version)(void);
static volatile LONG address, stop;
static BOOL wake_all;
struct result
{
unsigned int waits, success, timeout, other, stale, early;
};
static DWORD WINAPI waker_thread( void *arg )
{
while (!stop)
{
if (wake_all) pRtlWakeAddressAll( (const void *)&address );
else pRtlWakeAddressSingle( (const void *)&address );
}
return 0;
}
/* Race short waits against the waker. With probe, look for a pending alert after each wait; otherwise do the
* 100 ns wait on another address, which must time out. */
static void run_pass( LONGLONG wait_timeout, BOOL probe, unsigned int iterations, DWORD cap_ms, struct result *r )
{
static const LARGE_INTEGER zero;
LARGE_INTEGER timeout;
LONG compare = 0, other = 0;
DWORD start = GetTickCount();
NTSTATUS status;
unsigned int i;
memset( r, 0, sizeof(*r) );
for (i = 0; i < iterations && GetTickCount() - start < cap_ms; i++)
{
timeout.QuadPart = wait_timeout;
status = pRtlWaitOnAddress( (const void *)&address, &compare, sizeof(compare), &timeout );
r->waits++;
if (status == STATUS_SUCCESS) r->success++;
else if (status == STATUS_TIMEOUT) r->timeout++;
else r->other++;
if (probe)
{
if (pNtWaitForAlertByThreadId( NULL, &zero ) == STATUS_ALERTED) r->stale++;
}
else
{
timeout.QuadPart = -1;
if (pRtlWaitOnAddress( &other, &compare, sizeof(compare), &timeout ) != STATUS_TIMEOUT) r->early++;
}
}
}
int main( int argc, char **argv )
{
unsigned int iterations = argc > 1 ? atoi( argv[1] ) : 20000, total_stale = 0, total_early = 0, i;
DWORD cap_ms = (argc > 2 ? atoi( argv[2] ) : 3) * 1000;
HMODULE ntdll = GetModuleHandleA( "ntdll.dll" );
RTL_OSVERSIONINFOW ver = { sizeof(ver) };
struct result r;
HANDLE thread;
setvbuf( stdout, NULL, _IONBF, 0 ); /* show each pass as it completes, also through a pipe */
pRtlWaitOnAddress = (void *)GetProcAddress( ntdll, "RtlWaitOnAddress" );
pRtlWakeAddressSingle = (void *)GetProcAddress( ntdll, "RtlWakeAddressSingle" );
pRtlWakeAddressAll = (void *)GetProcAddress( ntdll, "RtlWakeAddressAll" );
pNtWaitForAlertByThreadId = (void *)GetProcAddress( ntdll, "NtWaitForAlertByThreadId" );
pRtlGetVersion = (void *)GetProcAddress( ntdll, "RtlGetVersion" );
pwine_get_version = (void *)GetProcAddress( ntdll, "wine_get_version" );
if (!pRtlWaitOnAddress || !pRtlWakeAddressSingle || !pRtlWakeAddressAll || !pNtWaitForAlertByThreadId)
{
fprintf( stderr, "ntdll lacks RtlWaitOnAddress or NtWaitForAlertByThreadId (needs Windows 8 or later)\n" );
return 1;
}
if (pRtlGetVersion) pRtlGetVersion( &ver );
printf( "OS %lu.%lu build %lu%s%s, %lu processors\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
pwine_get_version ? ", Wine " : "", pwine_get_version ? pwine_get_version() : "",
(unsigned long)GetActiveProcessorCount( ALL_PROCESSOR_GROUPS ) );
/* A pending alert from anything before us would be misread as ours. */
{
static const LARGE_INTEGER zero;
pNtWaitForAlertByThreadId( NULL, &zero );
}
for (i = 0; i < 8; i++)
{
LONGLONG wait_timeout = (i & 4) ? -1 : 0;
BOOL probe = !(i & 1);
wake_all = !!(i & 2);
printf( "timeout %3d ns, wake %-6s, %s: ", (int)-wait_timeout * 100, wake_all ? "all" : "single",
probe ? "probe" : "early" );
stop = 0;
thread = CreateThread( NULL, 0, waker_thread, NULL, 0, NULL );
run_pass( wait_timeout, probe, iterations, cap_ms, &r );
InterlockedExchange( &stop, 1 );
WaitForSingleObject( thread, INFINITE );
CloseHandle( thread );
printf( "%6u waits (%6u woken, %6u timed out, %u other)", r.waits, r.success, r.timeout, r.other );
if (probe) printf( ", %u stale alerts\n", r.stale );
else printf( ", %u early returns on another address\n", r.early );
total_stale += r.stale;
total_early += r.early;
}
printf( "total: %u stale alerts, %u early returns\n", total_stale, total_early );
return 0;
}
raced_wake_probe.exe 20000 3, then stale_wake.exe 15 8 poll|both|timed
Microsoft Windows [Version 10.0.26200.9457]
=== raced_wake_probe.exe 20000 3 ===
OS 10.0 build 26200, 4 processors
timeout 0 ns, wake single, probe: 20000 waits ( 19961 woken, 39 timed out, 0 other), 0 stale alerts
timeout 0 ns, wake single, early: 189 waits ( 160 woken, 29 timed out, 0 other), 0 early returns on another address
timeout 0 ns, wake all , probe: 20000 waits ( 19953 woken, 47 timed out, 0 other), 0 stale alerts
timeout 0 ns, wake all , early: 189 waits ( 183 woken, 6 timed out, 0 other), 0 early returns on another address
timeout 100 ns, wake single, probe: 20000 waits ( 20000 woken, 0 timed out, 0 other), 0 stale alerts
timeout 100 ns, wake single, early: 190 waits ( 190 woken, 0 timed out, 0 other), 0 early returns on another address
timeout 100 ns, wake all , probe: 20000 waits ( 20000 woken, 0 timed out, 0 other), 0 stale alerts
timeout 100 ns, wake all , early: 189 waits ( 189 woken, 0 timed out, 0 other), 0 early returns on another address
total: 0 stale alerts, 0 early returns
=== stale_wake.exe 15 8 poll ===
poll: 15 s, 8 workers: 100097 future waits, 0 returned while still pending (spurious)
=== stale_wake.exe 15 8 both ===
both: 15 s, 8 workers: 26073 future waits, 0 returned while still pending (spurious)
=== stale_wake.exe 15 8 timed ===
timed: 15 s, 8 workers: 85325 future waits, 0 returned while still pending (spurious)
For the record, the Wine side of the probe (raced_wake_probe.exe 20000 2 under Proton Experimental's wine, 16 processors) totalled 41 pending alerts and 59 early returns over the eight passes; with the patched ntdll (v4) it was 0 and 0.
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 18e61e4..acf2df5 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -881,6 +881,7 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
{
struct futex_queue *queue = get_futex_queue( addr );
struct futex_entry entry;
+ BOOL queued = FALSE;
NTSTATUS ret;
TRACE("addr %p cmp %p size %#Ix timeout %s\n", addr, cmp, size, debugstr_timeout( timeout ));
@@ -909,15 +910,25 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
ret = NtWaitForAlertByThreadId( NULL, timeout );
- /* We may have already been removed by a call to RtlWakeAddressSingle() or RtlWakeAddressAll(). */
- if (entry.addr)
+ /* We may have already been removed by a call to RtlWakeAddressSingle() or RtlWakeAddressAll(). They clear
+ * the address last, with release semantics: once it is NULL the waker is done with the entry. */
+ if (ReadPointerAcquire( (void * const volatile *)&entry.addr ))
{
spin_lock( &queue->lock );
- if (entry.addr)
+ if ((queued = entry.addr != NULL))
list_remove( &entry.entry );
spin_unlock( &queue->lock );
}
+ if (!queued && ret == STATUS_TIMEOUT)
+ {
+ /* A waker removed us as the wait timed out: we have been woken, and the waker alerts us right after
+ * releasing the queue lock. Take that alert, as Windows does, or it would end this thread's next wait
+ * early, whatever it waits for. */
+ NtWaitForAlertByThreadId( NULL, NULL );
+ ret = STATUS_SUCCESS;
+ }
+
TRACE("returning %#lx\n", ret);
if (ret == STATUS_ALERTED) ret = STATUS_SUCCESS;
@@ -947,14 +958,17 @@ void WINAPI RtlWakeAddressAll( const void *addr )
{
if (entry->addr == addr)
{
- entry->addr = NULL;
- list_remove( &entry->entry );
if (count == ARRAY_SIZE(tids))
{
NtAlertMultipleThreadByThreadId( tids, count, NULL, NULL );
count = 0;
}
tids[count++] = (HANDLE)(ULONG_PTR)entry->tid;
+ list_remove( &entry->entry );
+
+ /* The entry is on the waiter's stack, and the waiter may return as soon as it sees the address
+ * cleared, so this must be our last access to it. */
+ WritePointerRelease( (void * volatile *)&entry->addr, NULL );
}
}
@@ -994,8 +1008,11 @@ void WINAPI RtlWakeAddressSingle( const void *addr )
/* Remove this entry from the queue, so that a simultaneous call to
* RtlWakeAddressSingle() will not also wake it—two simultaneous
* calls must wake at least two waiters if they exist. */
- entry->addr = NULL;
list_remove( &entry->entry );
+
+ /* The entry is on the waiter's stack, and the waiter may return as soon as it sees the address
+ * cleared, so this must be our last access to it. */
+ WritePointerRelease( (void * volatile *)&entry->addr, NULL );
break;
}
}
diff --git a/dlls/ntdll/tests/sync.c b/dlls/ntdll/tests/sync.c
index dcbb8b1..0239280 100644
--- a/dlls/ntdll/tests/sync.c
+++ b/dlls/ntdll/tests/sync.c
@@ -615,6 +615,85 @@ static void test_wait_on_address(void)
ok(address == 0, "got %s\n", wine_dbgstr_longlong(address));
}
+struct wait_on_address_waker
+{
+ LONG address;
+ volatile LONG stop;
+ BOOL wake_all;
+};
+
+static DWORD WINAPI wait_on_address_waker_thread( void *arg )
+{
+ struct wait_on_address_waker *waker = arg;
+
+ while (!waker->stop)
+ {
+ if (waker->wake_all) pRtlWakeAddressAll( &waker->address );
+ else pRtlWakeAddressSingle( &waker->address );
+ }
+ return 0;
+}
+
+static void test_wait_on_address_raced_wake(void)
+{
+ static const LONGLONG timeouts[] = {0, -1};
+ static const LARGE_INTEGER zero;
+ struct wait_on_address_waker waker;
+ unsigned int i, count, pending, early, failed;
+ LARGE_INTEGER timeout;
+ LONG compare = 0, other = 0;
+ NTSTATUS status;
+ HANDLE thread;
+ DWORD start;
+
+ if (!pRtlWaitOnAddress)
+ {
+ win_skip("RtlWaitOnAddress not supported, skipping test\n");
+ return;
+ }
+
+ /* A wake that races the end of a short wait may be taken by that wait, but it must not leave an alert
+ * pending on the thread, which would end its next wait on anything early. */
+ for (i = 0; i < ARRAY_SIZE(timeouts) * 2; i++)
+ {
+ winetest_push_context( "timeout %s, %s", wine_dbgstr_longlong( timeouts[i / 2] ),
+ i % 2 ? "wake all" : "wake single" );
+
+ waker.address = 0;
+ waker.stop = 0;
+ waker.wake_all = i % 2;
+ thread = CreateThread( NULL, 0, wait_on_address_waker_thread, &waker, 0, NULL );
+
+ pending = early = failed = 0;
+ start = GetTickCount();
+ for (count = 0; count < 20000 && GetTickCount() - start < 1000; count++)
+ {
+ timeout.QuadPart = timeouts[i / 2];
+ status = pRtlWaitOnAddress( &waker.address, &compare, sizeof(compare), &timeout );
+ if (status != STATUS_SUCCESS && status != STATUS_TIMEOUT) failed++;
+
+ if (pNtWaitForAlertByThreadId)
+ {
+ if (pNtWaitForAlertByThreadId( NULL, &zero ) == STATUS_ALERTED) pending++;
+ }
+ else
+ {
+ timeout.QuadPart = -1;
+ if (pRtlWaitOnAddress( &other, &compare, sizeof(compare), &timeout ) != STATUS_TIMEOUT) early++;
+ }
+ }
+
+ waker.stop = 1;
+ WaitForSingleObject( thread, INFINITE );
+ CloseHandle( thread );
+
+ ok( !failed, "%u of %u waits failed\n", failed, count );
+ ok( !pending, "%u of %u waits left an alert pending\n", pending, count );
+ ok( !early, "%u of %u waits on another address returned early\n", early, count );
+ winetest_pop_context();
+ }
+}
+
static HANDLE thread_ready, thread_done;
static DWORD WINAPI resource_shared_thread(void *arg)
@@ -1474,6 +1553,7 @@ START_TEST(sync)
pRtlBarrier = (void *)GetProcAddress(module, "RtlBarrier");
test_wait_on_address();
+ test_wait_on_address_raced_wake();
test_event();
test_mutant();
test_semaphore();
I know this is for Space Marine 2, but I did want to confirm that on Control Resonant and Alan Wake 2, I was experiencing the same bug on NVIDIA-SMI 615.71.09 KMD Version: 615.71.09 CUDA UMD Version: 13.4 using an RTX 3080. I'm on the latest Bazzite 44, but my journalctl logs looked the same (xid 109) and also had err:winevulkan:signaller_worker error waiting for semaphores, vr -4.
Installing pyroveil and configuring it like this:
{
"version": 2,
"type": "pyroveil",
"matches": [
{ "spirvExecutionModel": 5365, "action": { "glsl-roundtrip": true } }
],
"disabledExtensions": [ "VK_NV_raw_access_chains" ]
}
did indeed stop my freezes (audio still played) on both games. Just wanted to add to the pile here. I can pull whatever logs if asked.
@jegglest The wine devs don't care even with a deep analysis, saying that it was misdiagnosed.
I don't agree on their posture, I think AI can be powerful and a great tool on the right hands.
I recommend you to share your analysis directly on the Proton repo, don't waste your time.
@JMarcosHP we haven't heard a whole lot from the wine developers yet. I think I'm handling the community well, the patch is public, works for me, and I've supplied a test that demonstrates the behavioral differences between windows and wine. If the implementation I've chosen is not the right way to do it, the wine developers are free to do something else, or, frankly to ignore it. That's their choice.
@Erfboom if you try this patch and it fixes your issues, that's great. Otherwise, I think those reports don't belong in this issue.
Understood! I'll give the patch a try. Thanks!
I can independently confirm the Retail.exe+0x2158FEE / RCX = 0x3 crash described above.
I preserved and parsed four Space Marine 2 minidumps from Retail 14.2 on Fedora/NVIDIA. All four have the same signature:
2026-09-17 0xC0000005 READ Retail.exe+0x2158FEE RCX=0x3 RDX=0x0 target=0xB
2026-09-21 0xC0000005 READ Retail.exe+0x2158FEE RCX=0x3 RDX=0x0 target=0xB
2026-09-21 0xC0000005 READ Retail.exe+0x2158FEE RCX=0x3 RDX=0x3 target=0x23
2026-09-30 0xC0000005 READ Retail.exe+0x2158FEE RCX=0x3 RDX=0x6 target=0x3B
The scenes were different:
pve_daemonhostpve_tyrantpve_acid_bombpve_dreadBuild in all four reports:
Retail_14.2.PATCH.1339092/1344629.PATCH14
I also disassembled the faulting instruction:
142158fee: cmpl $0x1,0x8(%rcx,%rdx,8)
The effective addresses calculated from the exception contexts exactly match the addresses reported by the minidumps.
For example, the latest crash had:
RCX = 0x3
RDX = 0x6
0x3 + (0x6 * 8) + 8 = 0x3B
So this appears to be the same crash described in the root-cause analysis above.
System for the latest occurrence:
There was no NVIDIA Xid, GPU reset, system OOM, or Linux-side coredump around the latest occurrence.
I have the original CrashDump.dmp, error.yaml, and screenshots for all four preserved occurrences if they would be useful for further testing.
Is this issue still present on patch 15?
Is this issue still present on patch 15?
Yes! Just tested it and crashed with the empy pop-up window
v6: a second ntsync bug (mutex abandonment) fixed on the server side, and 9.4 hours without a crash
In-game. Since my first patched build on 2026-09-26 I have played 13 sessions, 565 minutes in total (about 9.4 hours), on the patched builds v1 to v6 with no crash, against 8 crashes in about 7 h 20 min before, roughly one per 55 minutes. At that rate 9.4 crash-free hours by luck would be about a one-in-thirty-thousand event. Today's two sessions on v6 (15 and 80 minutes) were the first with the full set below; in the 80-minute session the raced wake that the ntdll fix handles happened at least 5,000 times, every one a zero-timeout WaitOnAddress() from the game's tcmalloc spinlock, and no stale alert got through.
The new bug. Running Wine's kernel32:sync conformance suite on the patched build, two failures in test_mutex() that I had taken for pre-existing noise turned out to be a real ntsync bug, in Proton's server and in upstream Wine alike. With /dev/ntsync, a thread that dies while owning a mutex whose last handle its process has already closed never abandons it, and a thread still waiting on that mutex blocks forever. The end of test_mutex() is exactly that sequence (close the handle, TerminateThread() the owner, expect WAIT_ABANDONED from the waiter) and fails at sync.c:393 and :397 in Proton's tree. It is unrelated to the crash; it is just the next thing the test suite pointed at.
Cause: a thread waiting on an in-process object holds only a duplicate of the ntsync fd, no server reference. When the process closes its last handle the server destroys its object and the mutex drops off the list that abandon_inproc_mutexes() sends NTSYNC_IOC_MUTEX_KILL to on thread death. The kernel object lives on through the waiter's fd, still owned by a dead thread id, and nothing ever kills it. With the handle kept open, or with PROTON_NO_NTSYNC=1, it works; on Windows 11 (same VM as my previous comment) the waiter gets WAIT_ABANDONED 0.1 to 0.7 ms after the terminate, 5 of 5 runs. A 32-bit build of the probe behaves the same on stock Proton, so it is the server, not either architecture's ntdll.
Fix (two server commits, diff below):
NTSYNC_IOC_MUTEX_READ), keep the fd on an orphan list; kill orphans along with the live mutexes on thread death and close them once unowned. Unowned mutexes are closed as before.NtClose() (or a close-source DuplicateHandle) finds another thread still using the cached mutex, it passes the cache entry's serial to the server with the close_handle request, the server keeps a reference under that serial, and the entry's last user releases it with a new release_inproc_sync request; a process's records go away with the process. The common close path has no extra server call. Windows abandons the mutex in this case too (3 of 3 runs of the wait-all probe).Results: kernel32:sync 0 failures in 4 runs (stock: the 2 test_mutex failures), ntdll:sync 441/441, the timed probe below passes its three cases 30 of 30 in both 64- and 32-bit builds (stock: the closed-handle and wait-all cases never return), and the server's fd count is the same after the runs as before.
Build notes, relevant for Proton specifically. Part 2 adds two request fields and one request, so it bumps the server protocol version, and every unix-side ntdll.so must match. Proton runs this game's 32-bit launcher stub (Warhammer 40000 Space Marine 2.exe, which starts the 64-bit EAC bootstrap and the game) the classic way on i386-unix/ntdll.so, so a build that only replaced the 64-bit side stopped the game from starting until I rebuilt the 32-bit unix ntdll as well. My build replaces ntdll.dll and ntdll.so for both architectures plus wineserver, and leaves the other unix libraries stock; for that to work the new request is appended after all existing ones, so that the request numbers win32u.so and friends use are unchanged. A full Proton build has neither concern. The ntdll patches are the three from my previous comment, unchanged.
I'll file the mutex bug with Wine as well and link it here.
tools/make_requests after applying)diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c
index 112157b..faba490 100644
--- a/dlls/ntdll/unix/server.c
+++ b/dlls/ntdll/unix/server.c
@@ -1863,6 +1863,8 @@ NTSTATUS WINAPI NtAllocateReserveObject( HANDLE *handle, const OBJECT_ATTRIBUTES
NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source, HANDLE dest_process, HANDLE *dest,
ACCESS_MASK access, ULONG attributes, ULONG options )
{
+ struct inproc_sync *cache = NULL;
+ unsigned int serial = 0;
sigset_t sigset;
unsigned int ret;
int fd = -1;
@@ -1899,7 +1901,7 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source, HANDLE
if (options & DUPLICATE_CLOSE_SOURCE)
{
fd = remove_fd_from_cache( source );
- close_inproc_sync( source );
+ cache = close_inproc_sync_begin( source, &serial );
}
SERVER_START_REQ( dup_handle )
@@ -1910,12 +1912,14 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source, HANDLE
req->access = access;
req->attributes = attributes;
req->options = options;
+ req->inproc_serial = serial;
if (!(ret = wine_server_call( req )))
{
if (dest) *dest = wine_server_ptr_handle( reply->handle );
}
}
SERVER_END_REQ;
+ if (cache) close_inproc_sync_end( cache, serial );
server_leave_uninterrupted_section( &fd_cache_mutex, &sigset );
@@ -1958,6 +1962,8 @@ NTSTATUS WINAPI NtCompareTokens( HANDLE first, HANDLE second, BOOLEAN *equal )
*/
NTSTATUS WINAPI NtClose( HANDLE handle )
{
+ struct inproc_sync *cache;
+ unsigned int serial;
sigset_t sigset;
HANDLE port;
unsigned int ret;
@@ -1973,14 +1979,16 @@ NTSTATUS WINAPI NtClose( HANDLE handle )
/* always remove the cached fd; if the server request fails we'll just
* retrieve it again */
fd = remove_fd_from_cache( handle );
- close_inproc_sync( handle );
+ cache = close_inproc_sync_begin( handle, &serial );
SERVER_START_REQ( close_handle )
{
req->handle = wine_server_obj_handle( handle );
+ req->inproc_serial = serial;
ret = wine_server_call( req );
}
SERVER_END_REQ;
+ if (cache) close_inproc_sync_end( cache, serial );
server_leave_uninterrupted_section( &fd_cache_mutex, &sigset );
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c
index 67ab945..b0e4a10 100644
--- a/dlls/ntdll/unix/sync.c
+++ b/dlls/ntdll/unix/sync.c
@@ -542,8 +542,11 @@ struct inproc_sync
unsigned int access; /* handle access rights */
unsigned short type; /* enum inproc_sync_type as short to save space */
unsigned short closed; /* fd has been closed but sync is still referenced */
+ unsigned int serial; /* id of this cache entry for the server, 0 if not cached */
};
+static LONG next_inproc_sync_serial;
+
#define INPROC_SYNC_CACHE_BLOCK_SIZE (65536 / sizeof(struct inproc_sync))
#define INPROC_SYNC_CACHE_ENTRIES 128
@@ -604,6 +607,7 @@ static struct inproc_sync *cache_inproc_sync( HANDLE handle, struct inproc_sync
cache->access = sync->access;
cache->type = sync->type;
cache->closed = sync->closed;
+ while (!(cache->serial = InterlockedIncrement( &next_inproc_sync_serial ))) ;
/* Make sure we set the other members before the refcount; this store needs
* release semantics [paired with the load in get_cached_inproc_sync()].
* Set the refcount to 2 (one for the handle, one for the caller). */
@@ -628,15 +632,31 @@ static inline LONG interlocked_inc_if_nonzero( LONG *dest )
return val;
}
+static void release_detached_inproc_sync( unsigned int serial )
+{
+ SERVER_START_REQ( release_inproc_sync )
+ {
+ req->serial = serial;
+ wine_server_call( req );
+ }
+ SERVER_END_REQ;
+}
+
static void release_inproc_sync( struct inproc_sync *sync )
{
- /* save the fd now; as soon as the refcount hits 0 we cannot
+ /* save the fd and serial now; as soon as the refcount hits 0 we cannot
* access the cache anymore */
int fd = sync->fd;
+ unsigned int serial = sync->serial;
LONG ref = InterlockedDecrement( &sync->refcount );
assert( ref >= 0 );
- if (!ref) close( fd );
+ if (ref) return;
+ close( fd );
+ /* The handle was closed while the object was in use (NtClose() drops the
+ * handle's reference last), and close_inproc_sync_begin() had the server
+ * keep the object under this serial: let it go now. */
+ if (serial) release_detached_inproc_sync( serial );
}
static struct inproc_sync *get_cached_inproc_sync( HANDLE handle )
@@ -682,6 +702,7 @@ static NTSTATUS get_server_inproc_sync( HANDLE handle, struct inproc_sync *sync
sync->access = reply->access;
sync->type = reply->type;
sync->closed = 0;
+ sync->serial = 0;
}
}
SERVER_END_REQ;
@@ -761,23 +782,47 @@ extern NTSTATUS check_signal_access( struct inproc_sync *sync )
}
/* caller must hold fd_cache_mutex */
-void close_inproc_sync( HANDLE handle )
+/* First half of closing a handle, before the server request: drop the cache
+ * entry and find out whether another thread is still using the object.
+ * Returns the entry, with a reference held, for close_inproc_sync_end(). */
+struct inproc_sync *close_inproc_sync_begin( HANDLE handle, unsigned int *serial )
{
struct inproc_sync *cache;
+ *serial = 0;
if (do_fsync())
{
fsync_close( handle );
- return;
- }
- if (inproc_device_fd < 0) return;
- if ((cache = get_cached_inproc_sync( handle )))
- {
- cache->closed = 1;
- /* once for the reference we just grabbed, and once for the handle */
- release_inproc_sync( cache );
- release_inproc_sync( cache );
+ return NULL;
}
+ if (inproc_device_fd < 0) return NULL;
+ if (!(cache = get_cached_inproc_sync( handle ))) return NULL;
+ cache->closed = 1;
+ /* One reference is the handle's and one is ours; any more belong to
+ * threads in the middle of an operation, typically a wait. Such a thread
+ * can still acquire a mutex through the fd, and the server must then know
+ * the mutex to abandon it if the thread dies, so have the server keep the
+ * object under this entry's serial until the last user releases it. */
+ if (cache->type == INPROC_SYNC_MUTEX && InterlockedCompareExchange( &cache->refcount, 0, 0 ) > 2)
+ *serial = cache->serial;
+ return cache;
+}
+
+/* Second half, after the server request; serial is what the request carried, or 0 */
+void close_inproc_sync_end( struct inproc_sync *cache, unsigned int serial )
+{
+ cache->serial = serial;
+ /* once for the reference we grabbed, and once for the handle */
+ release_inproc_sync( cache );
+ release_inproc_sync( cache );
+}
+
+void close_inproc_sync( HANDLE handle )
+{
+ struct inproc_sync *cache;
+ unsigned int serial;
+
+ if ((cache = close_inproc_sync_begin( handle, &serial ))) close_inproc_sync_end( cache, 0 );
}
static NTSTATUS inproc_release_semaphore( HANDLE handle, ULONG count, ULONG *prev_count )
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index 41163e0..a9608cb 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -418,6 +418,9 @@ extern NTSTATUS wow64_wine_spawnvp( void *args );
extern void dbg_init(void);
+struct inproc_sync;
+extern struct inproc_sync *close_inproc_sync_begin( HANDLE handle, unsigned int *serial );
+extern void close_inproc_sync_end( struct inproc_sync *cache, unsigned int serial );
extern void close_inproc_sync( HANDLE handle );
extern NTSTATUS call_user_apc_dispatcher( CONTEXT *context_ptr, unsigned int flags, ULONG_PTR arg1, ULONG_PTR arg2,
diff --git a/server/handle.c b/server/handle.c
index a88f94a..b417276 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -670,7 +670,15 @@ unsigned int get_handle_table_count( struct process *process )
/* close a handle */
DECL_HANDLER(close_handle)
{
- unsigned int err = close_handle( current->process, req->handle );
+ struct object *obj;
+ unsigned int err;
+
+ if (req->inproc_serial && (obj = get_handle_obj( current->process, req->handle, 0, NULL )))
+ {
+ detach_inproc_sync( current->process, obj, req->inproc_serial );
+ release_object( obj );
+ }
+ err = close_handle( current->process, req->handle );
set_error( err );
}
@@ -701,7 +709,17 @@ DECL_HANDLER(dup_handle)
}
/* close the handle no matter what happened */
if ((req->options & DUPLICATE_CLOSE_SOURCE) && (src != dst || req->src_handle != reply->handle))
+ {
+ struct object *obj;
+
+ if (req->inproc_serial && src == current->process
+ && (obj = get_handle_obj( src, req->src_handle, 0, NULL )))
+ {
+ detach_inproc_sync( src, obj, req->inproc_serial );
+ release_object( obj );
+ }
close_handle( src, req->src_handle );
+ }
release_object( src );
}
}
diff --git a/server/inproc_sync.c b/server/inproc_sync.c
index a7020ef..c70de28 100644
--- a/server/inproc_sync.c
+++ b/server/inproc_sync.c
@@ -23,6 +23,7 @@
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
@@ -75,6 +76,51 @@ struct inproc_sync
static struct list inproc_mutexes = LIST_INIT( inproc_mutexes );
+/* Mutexes whose server object was destroyed while a thread still owned them. A client can still hold
+ * a duplicate of the fd (a thread waiting on a handle that has since been closed), and the ntsync
+ * driver abandons a mutex only through NTSYNC_IOC_MUTEX_KILL on that mutex, so the fd is kept until
+ * the owner has released or abandoned it. */
+struct orphan_mutex
+{
+ struct list entry;
+ int fd;
+};
+
+static struct list orphan_mutexes = LIST_INIT( orphan_mutexes );
+
+static int inproc_mutex_owned( int fd )
+{
+ struct ntsync_mutex_args args = {0};
+ return !ioctl( fd, NTSYNC_IOC_MUTEX_READ, &args ) && args.owner;
+}
+
+static void prune_orphan_mutexes(void)
+{
+ struct orphan_mutex *orphan, *next;
+
+ LIST_FOR_EACH_ENTRY_SAFE( orphan, next, &orphan_mutexes, struct orphan_mutex, entry )
+ {
+ if (inproc_mutex_owned( orphan->fd )) continue;
+ list_remove( &orphan->entry );
+ close( orphan->fd );
+ free( orphan );
+ }
+}
+
+/* In-process syncs whose handle a process closed while one of its threads was still using the cached fd
+ * (typically a wait in progress). That thread can still acquire the mutex through the fd, so the server keeps
+ * the object, and with it the mutex's place on inproc_mutexes, until the client reports that the last user is
+ * done, or the process dies. */
+struct detached_sync
+{
+ struct list entry;
+ struct process *process; /* process that closed the handle; the record dies with it */
+ unsigned int serial; /* id chosen by the client, unique within the process */
+ struct inproc_sync *sync; /* the reference this record holds */
+};
+
+static struct list detached_syncs = LIST_INIT( detached_syncs );
+
static void inproc_sync_dump( struct object *obj, int verbose );
static int inproc_sync_signal( struct object *obj, unsigned int access, int signal );
static void inproc_sync_destroy( struct object *obj );
@@ -262,12 +308,25 @@ static void inproc_sync_destroy( struct object *obj )
assert( obj->ops == &inproc_sync_ops );
list_remove( &sync->entry );
if (do_fsync()) fsync_free_shm_idx( sync->fd );
- else close( sync->fd );
+ else if (sync->type == INPROC_SYNC_MUTEX && inproc_mutex_owned( sync->fd ))
+ {
+ struct orphan_mutex *orphan;
+
+ prune_orphan_mutexes();
+ if ((orphan = malloc( sizeof(*orphan) )))
+ {
+ orphan->fd = sync->fd;
+ list_add_tail( &orphan_mutexes, &orphan->entry );
+ }
+ else close( sync->fd );
+ }
+ else close( sync->fd );
}
void abandon_inproc_mutexes( thread_id_t tid )
{
struct inproc_sync *mutex;
+ struct orphan_mutex *orphan;
if (do_fsync())
{
@@ -278,6 +337,55 @@ void abandon_inproc_mutexes( thread_id_t tid )
LIST_FOR_EACH_ENTRY( mutex, &inproc_mutexes, struct inproc_sync, entry )
ioctl( mutex->fd, NTSYNC_IOC_MUTEX_KILL, &tid );
+ LIST_FOR_EACH_ENTRY( orphan, &orphan_mutexes, struct orphan_mutex, entry )
+ ioctl( orphan->fd, NTSYNC_IOC_MUTEX_KILL, &tid );
+ prune_orphan_mutexes();
+}
+
+void detach_inproc_sync( struct process *process, struct object *obj, unsigned int serial )
+{
+ struct object *sync;
+ struct detached_sync *detached;
+
+ if (!(sync = get_obj_sync( obj ))) return;
+ if (sync->ops == &inproc_sync_ops && ((struct inproc_sync *)sync)->type == INPROC_SYNC_MUTEX
+ && (detached = malloc( sizeof(*detached) )))
+ {
+ detached->process = process;
+ detached->serial = serial;
+ detached->sync = (struct inproc_sync *)sync; /* keeps the reference from get_obj_sync() */
+ list_add_tail( &detached_syncs, &detached->entry );
+ return;
+ }
+ release_object( sync );
+}
+
+unsigned int release_detached_inproc_sync( struct process *process, unsigned int serial )
+{
+ struct detached_sync *detached;
+
+ LIST_FOR_EACH_ENTRY( detached, &detached_syncs, struct detached_sync, entry )
+ {
+ if (detached->process != process || detached->serial != serial) continue;
+ list_remove( &detached->entry );
+ release_object( detached->sync );
+ free( detached );
+ return STATUS_SUCCESS;
+ }
+ return STATUS_INVALID_PARAMETER;
+}
+
+void release_process_inproc_syncs( struct process *process )
+{
+ struct detached_sync *detached, *next;
+
+ LIST_FOR_EACH_ENTRY_SAFE( detached, next, &detached_syncs, struct detached_sync, entry )
+ {
+ if (detached->process != process) continue;
+ list_remove( &detached->entry );
+ release_object( detached->sync );
+ free( detached );
+ }
}
static int get_obj_inproc_sync( struct object *obj, int *type )
@@ -341,6 +449,19 @@ void abandon_inproc_mutexes( thread_id_t tid )
{
}
+void detach_inproc_sync( struct process *process, struct object *obj, unsigned int serial )
+{
+}
+
+unsigned int release_detached_inproc_sync( struct process *process, unsigned int serial )
+{
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+void release_process_inproc_syncs( struct process *process )
+{
+}
+
static int get_obj_inproc_sync( struct object *obj, int *type )
{
return -1;
@@ -363,3 +484,8 @@ DECL_HANDLER(get_inproc_sync_fd)
release_object( obj );
}
+
+DECL_HANDLER(release_inproc_sync)
+{
+ set_error( release_detached_inproc_sync( current->process, req->serial ) );
+}
diff --git a/server/object.h b/server/object.h
index 21f5ea8..ff369a0 100644
--- a/server/object.h
+++ b/server/object.h
@@ -255,6 +255,9 @@ extern struct inproc_sync *create_inproc_event_sync( int manual, int signaled );
extern struct inproc_sync *create_inproc_semaphore_sync( unsigned int initial, unsigned int max );
extern struct inproc_sync *create_inproc_mutex_sync( thread_id_t owner, unsigned int count );
extern void abandon_inproc_mutexes( thread_id_t owner );
+extern void detach_inproc_sync( struct process *process, struct object *obj, unsigned int serial );
+extern unsigned int release_detached_inproc_sync( struct process *process, unsigned int serial );
+extern void release_process_inproc_syncs( struct process *process );
extern void signal_inproc_sync( struct inproc_sync *sync );
extern void reset_inproc_sync( struct inproc_sync *sync );
diff --git a/server/process.c b/server/process.c
index 287718a..130d2ca 100644
--- a/server/process.c
+++ b/server/process.c
@@ -808,6 +808,7 @@ static void process_destroy( struct object *obj )
assert( !process->sigkill_timeout ); /* timeout should hold a reference to the process */
close_process_handles( process );
+ release_process_inproc_syncs( process );
set_process_startup_state( process, STARTUP_ABORTED );
if (process->job)
@@ -1013,6 +1014,7 @@ static void process_killed( struct process *process )
process->desktop = 0;
cancel_terminating_process_asyncs( process );
close_process_handles( process );
+ release_process_inproc_syncs( process );
if (process->idle_event) release_object( process->idle_event );
process->idle_event = NULL;
assert( !process->console );
diff --git a/server/protocol.def b/server/protocol.def
index f1b7dee..c53894f 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1383,6 +1383,7 @@ struct cpu_topology_override
/* Close a handle for the current process */
@REQ(close_handle)
obj_handle_t handle; /* handle to close */
+ unsigned int inproc_serial; /* if nonzero, keep the in-process sync (still used by another thread) under this serial */
@END
@@ -1404,6 +1405,7 @@ struct cpu_topology_override
unsigned int access; /* wanted access rights */
unsigned int attributes; /* object attributes */
unsigned int options; /* duplicate options */
+ unsigned int inproc_serial; /* as for close_handle, when closing the source */
@REPLY
obj_handle_t handle; /* duplicated handle in dst process */
@END
@@ -4358,3 +4360,10 @@ enum fsync_type
unsigned int shm_idx;
@REPLY
@END
+
+
+/* Stop keeping an in-process sync that close_handle / dup_handle kept: its last user is done.
+ * Appended after every other request so that existing request numbers stay the same. */
+@REQ(release_inproc_sync)
+ unsigned int serial; /* serial given to close_handle / dup_handle */
+@END
mutex_abandon.c — the timed probe; build with x86_64-w64-mingw32-gcc -O2 -D__USE_MINGW_ANSI_STDIO=1 -o mutex_abandon.exe mutex_abandon.c (or i686-w64-mingw32-gcc for the 32-bit build); mutex_abandon.exe [close|keep|waitall] [iterations]/* Timed version of the end of kernel32:sync test_mutex(), plus one corner case. Prints how long each step takes.
*
* Usage: mutex_abandon.exe [close|keep|waitall] [iterations]
* close (default): a thread owns a mutex and blocks; a second thread waits on the mutex; the mutex handle is
* closed; the owner is killed with TerminateThread(). The waiter must get WAIT_ABANDONED.
* keep: the same with the mutex handle kept open.
* waitall: the mutex is unowned when its handle is closed, and two threads are blocked in wait-all calls
* on it, each with its own unset event. Setting event A lets thread A take the mutex; A is then
* killed; setting event B must give thread B the abandoned mutex.
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static HANDLE mutex, start_event, stop_event, event_a, event_b;
static LARGE_INTEGER freq, t0;
static double ms(void)
{
LARGE_INTEGER t;
QueryPerformanceCounter(&t);
return (t.QuadPart - t0.QuadPart) * 1000.0 / freq.QuadPart;
}
static const char *abandoned(DWORD ret)
{
return (ret >= WAIT_ABANDONED_0 && ret < WAIT_ABANDONED_0 + 2) ? " (abandoned)" : "";
}
static DWORD WINAPI owner_proc(void *arg)
{
DWORD ret = WaitForSingleObject(mutex, INFINITE);
printf("%9.1f ms owner: mutex wait returned %#lx\n", ms(), ret);
SetEvent(start_event);
ret = WaitForSingleObject(stop_event, INFINITE);
printf("%9.1f ms owner: stop_event wait returned %#lx (must not happen)\n", ms(), ret);
return 0;
}
static DWORD WINAPI waiter_proc(void *arg)
{
DWORD ret = WaitForSingleObject(mutex, INFINITE);
printf("%9.1f ms waiter: mutex wait returned %#lx%s\n", ms(), ret, abandoned(ret));
SetEvent(start_event);
ret = WaitForSingleObject(stop_event, INFINITE);
printf("%9.1f ms waiter: stop_event wait returned %#lx\n", ms(), ret);
return 0;
}
static DWORD WINAPI waitall_a_proc(void *arg)
{
HANDLE objs[2] = { mutex, event_a };
DWORD ret = WaitForMultipleObjects(2, objs, TRUE, INFINITE);
printf("%9.1f ms A: wait-all on mutex + event A returned %#lx\n", ms(), ret);
SetEvent(start_event);
ret = WaitForSingleObject(stop_event, INFINITE);
printf("%9.1f ms A: stop_event wait returned %#lx (must not happen)\n", ms(), ret);
return 0;
}
static DWORD WINAPI waitall_b_proc(void *arg)
{
HANDLE objs[2] = { mutex, event_b };
DWORD ret = WaitForMultipleObjects(2, objs, TRUE, INFINITE);
printf("%9.1f ms B: wait-all on mutex + event B returned %#lx%s\n", ms(), ret, abandoned(ret));
SetEvent(start_event);
ret = WaitForSingleObject(stop_event, INFINITE);
printf("%9.1f ms B: stop_event wait returned %#lx\n", ms(), ret);
return 0;
}
static int step(const char *what, DWORD ret, DWORD expect)
{
printf("%9.1f ms main: %s %#lx (expect %#lx)%s\n", ms(), what, ret, expect, ret == expect ? "" : " <-- FAILED");
return ret != expect;
}
static void create_events(void)
{
QueryPerformanceCounter(&t0);
start_event = CreateEventW(NULL, FALSE, FALSE, NULL);
stop_event = CreateEventW(NULL, FALSE, FALSE, NULL);
event_a = CreateEventW(NULL, FALSE, FALSE, NULL);
event_b = CreateEventW(NULL, FALSE, FALSE, NULL);
mutex = CreateMutexA(NULL, FALSE, NULL);
}
static void close_events(void)
{
CloseHandle(start_event);
CloseHandle(stop_event);
CloseHandle(event_a);
CloseHandle(event_b);
}
static int run(int close_mutex)
{
HANDLE owner, waiter;
int failures = 0;
create_events();
owner = CreateThread(NULL, 0, owner_proc, NULL, 0, NULL);
failures += step("owner started, start_event wait", WaitForSingleObject(start_event, 1000), 0);
waiter = CreateThread(NULL, 0, waiter_proc, NULL, 0, NULL);
failures += step("waiter blocked, start_event wait", WaitForSingleObject(start_event, 100), WAIT_TIMEOUT);
if (close_mutex)
{
CloseHandle(mutex);
failures += step("mutex handle closed, start_event wait", WaitForSingleObject(start_event, 100), WAIT_TIMEOUT);
}
printf("%9.1f ms main: TerminateThread(owner) -> %d\n", ms(), TerminateThread(owner, 0));
failures += step("owner thread handle wait", WaitForSingleObject(owner, 5000), 0);
failures += step("start_event wait (waiter got the mutex)", WaitForSingleObject(start_event, 5000), 0);
SetEvent(stop_event);
failures += step("waiter thread handle wait", WaitForSingleObject(waiter, 5000), 0);
CloseHandle(owner);
CloseHandle(waiter);
if (!close_mutex) CloseHandle(mutex);
close_events();
return failures;
}
static int run_waitall(void)
{
HANDLE a, b;
int failures = 0;
create_events();
a = CreateThread(NULL, 0, waitall_a_proc, NULL, 0, NULL);
b = CreateThread(NULL, 0, waitall_b_proc, NULL, 0, NULL);
failures += step("A and B blocked, start_event wait", WaitForSingleObject(start_event, 100), WAIT_TIMEOUT);
CloseHandle(mutex); /* nobody owns the mutex here */
failures += step("mutex handle closed, start_event wait", WaitForSingleObject(start_event, 100), WAIT_TIMEOUT);
SetEvent(event_a);
failures += step("event A set, start_event wait (A owns the mutex)", WaitForSingleObject(start_event, 1000), 0);
printf("%9.1f ms main: TerminateThread(A) -> %d\n", ms(), TerminateThread(a, 0));
failures += step("A thread handle wait", WaitForSingleObject(a, 5000), 0);
SetEvent(event_b);
failures += step("event B set, start_event wait (B got the abandoned mutex)", WaitForSingleObject(start_event, 5000), 0);
SetEvent(stop_event);
failures += step("B thread handle wait", WaitForSingleObject(b, 5000), 0);
CloseHandle(a);
CloseHandle(b);
close_events();
return failures;
}
int main(int argc, char **argv)
{
const char *mode = argc > 1 ? argv[1] : "close";
int iterations = argc > 2 ? atoi(argv[2]) : 1, i, failures = 0;
setvbuf(stdout, NULL, _IONBF, 0);
QueryPerformanceFrequency(&freq);
if (strcmp(mode, "close") && strcmp(mode, "keep") && strcmp(mode, "waitall"))
{
printf("usage: mutex_abandon.exe [close|keep|waitall] [iterations]\n");
return 2;
}
printf("mode: %s, %d iteration(s)\n", mode, iterations);
for (i = 0; i < iterations; i++)
{
printf("--- iteration %d\n", i + 1);
if (!strcmp(mode, "waitall")) failures += run_waitall();
else failures += run(!strcmp(mode, "close"));
}
printf("%d failed step(s)\n", failures);
return failures;
}
@Elthz Your crash is the one analysed above, in every file you attached:
crash_data.zip and the 2026-09-22 report) record an access violation at Retail.exe+0x2158FEE on the resFILE_LOADER thread with rcx=3, the signature from my first comment.dispatch_exception code=c0000005 ... addr=0000000142158FEE line (OP2 at 6580 s, Siege at 1386 s); OP1 ended without a captured fault.So it is not EAC, the GPU or memory. The error 1726 / RPC_S_SERVER_UNAVAILABLE lines appear only after the fault, when the services process loses its connection to the dying game, and the vkd3d-proton "view map pressure" warnings show up in all your logs long before the crash (and in mine). The crash dialog staying up while the game carries on for a while is what it looks like when the file-loader thread dies.
What it is: the game waits on a future with a single SleepConditionVariableCS(INFINITE), and on Wine that wait returns early, because a wake that races a zero-timeout WaitOnAddress() from the game's allocator leaves a stale thread alert behind. The read callback then writes into a stack frame that no longer exists. On Windows the same wait does not return early: 0 early returns in 100,000 on Windows 11 against 13% on Wine, same program, same machine. Windows' own implementation takes the racing wake instead of leaving it pending, and this game has run on that for a year. It crashes here because Wine behaves differently from Windows at that spot, and that is what needs fixing. The fix is small (patches in my comments above) and has given me 9.4 hours without a crash so far.
What helps today:
Filed the mutex abandonment bug upstream as https://bugs.winehq.org/show_bug.cgi?id=60417 (Wine, wineserver), with the analysis, the Windows measurements and the fix approach in prose; the patches above are the prototype. Wine bug 60397 remains the one for the stale thread alert behind the crash.
@jegglest thank you for the answer, hopefully your fix is implemented swiftly in wine/proton.
@jegglest I compiled the prototype with the 2 fixes you posted with Valve's wine, and it fixed the crashing for me. I also compiled with the 1st fix only, which also worked. I played with both for several hours without restarting the game and without any crashes, while earlier they happened at a rate of around 1-3 per hour.
May I share the prototype Proton fix with others to download, put in the right folder, and have it available as a Proton compatibility tool, or would you prefer to keep it under wraps until it's implemented officially? I sent you access to the repository.
@jegglest please open a PR here on proton repo or valve's wine for these 2 fixes.
In general, any changes that can go to upstream wine, should go upstream first, and https://gitlab.winehq.org/wine/wine/-/wikis/Developer-FAQ#can-i-contribute-code-generated-by-a-large-language-model-llm-tool should be taken into consideration while doing that. Over time, we want the difference between upstream wine and Proton to shrink, so that Proton remains maintainable.
The developers will not take any action, even after the patches fixed both issues and the theory proposed by the LLM's diagnosis was correct, contrary to what they assumed without checking it or taking the time to verify it on their own, as users have done in this case.
So what alternative do we have? I'm sorry, but their arguments sound very poor to me compared to what these users have done to contribute.
If anyone has a different opinion, I'm open to hearing it.
@Jpokul yes, you can share the prototype proton, no problem! The first patch fixes space marine 2. The second patch is an issue I just stumbled across when vetting the first patch, a regression introduced with ntsync, unrelated to space marine 2 but... it seemed like an issue in need of being fixed.
@kisak-valve I have provided the bug report, reasoning, and code that can independently reproduce the problems without having to run Space Marine 2, to Wine. I have read the guidelines, LLMs are only banned from code contributions, they aren't banned from discussion or diagnosis. They can implement a fix without using an LLM if they choose. But so far, we don't have real engagement. Like @JMarcosHP, I'm not sure where to take it from here.
I made the compiled build available at https://github.com/Jpokul/prototype_SM2_proton_fix_patch14-15
Instructions on how to use it are on the repository page.
@Erfboom, it's named SM2 fix, but other games can be run with it as well if you haven't compiled it yourself.
I made the compiled build available at https://github.com/Jpokul/prototype_SM2_proton_fix_patch14-15
Instructions on how to use it are on the repository page.
@Erfboom, it's named SM2 fix, but other games can be run with it as well if you haven't compiled it yourself.
Thanks! I've tried a session 3+ hours, it works!
I made the compiled build available at https://github.com/Jpokul/prototype_SM2_proton_fix_patch14-15
Instructions on how to use it are on the repository page.
@Erfboom, it's named SM2 fix, but other games can be run with it as well if you haven't compiled it yourself.
Thanks for your hard work ♥️, I'll try it now.
So, with PROTON_NO_NTSYNC=1 there are no crashes? Does anybody try this?
nvm, doesn't work
I made the compiled build available at https://github.com/Jpokul/prototype_SM2_proton_fix_patch14-15
Instructions on how to use it are on the repository page.
@Erfboom, it's named SM2 fix, but other games can be run with it as well if you haven't compiled it yourself.
Thank you @Jpokul and @jegglest for your work. Played for several hours including 25 waves of siege, no crashes.
I made the compiled build available at https://github.com/Jpokul/prototype_SM2_proton_fix_patch14-15
Instructions on how to use it are on the repository page.
@Erfboom, it's named SM2 fix, but other games can be run with it as well if you haven't compiled it yourself.
By the emperor, thank you so much this finally fixed it. I played 4 hours non-stop of operations and 15 waves of siege without a single crash when previously I would crash within an hour.
I made the compiled build available at https://github.com/Jpokul/prototype_SM2_proton_fix_patch14-15
Instructions on how to use it are on the repository page.
@Erfboom, it's named SM2 fix, but other games can be run with it as well if you haven't compiled it yourself.
Sadly, this is using FSR3 on Navi32/RDNA3. Override with SLO didn't work. Any chance this gets FSR4 support?
The goal is for proton to accept the patches, which will then be adopted by the proton derivatives.
I would like to also confirm, that this patched Proton version is working. Also Played nearly 3 hours without any special start-parameters, without any issues.
To bad the Imperator condemns all AI as heresy.
Thank you so much, did 2 hours and no crashes so far.
Fedora 44 7.2.8-200.fc44.x86_64
Same here, I played a total of 6h, no crashes.
Also Fedora 44, Linux 7.2.8-200.fc44.x86_64, KDE on Wayland
Unfortunately it did not help to fix the crashes for me.
PikaOS 4 x86_64
Linux 7.2.6-pikaos
GNOME 51.0 (Wayland)
@defaultuser321 if you can supply crash info like @Elthz did above, we can figure out what's going on, probably.
As a reminder:
If a game crashes, some logs should be generated automatically to
~/.local/share/Steam/steamapps/compatdata/2183900/pfx/drive_c/users/steamuser/AppData/Local/Saber/Space Marine 2/client/reports/
You can also run the game with PROTON_LOG=1 %command% set in launch options before launching the game and before the crash occurs, and then log will be saved in the home directory.
The path "/mnt/Data/SteamLibrary/steamapps/compatdata/2183900/pfx/drive_c/users/steamuser/AppData/Local/Saber/Space Marine 2/client/reports" exists, there's 17 report folders (latest are report_2026_10_06_20_19_05_pid364 & report_2026_10_06_20_19_23_pid364), but all folders are empty.
I presume that log is not created since game does not crash with any error, it just freeze and system offers termination after some time when game's not responding.
Proton log attached -> 104MB unpacked / 5MB packed
Let me know if you need any additional info.
Sadly, this is using FSR3 on Navi32/RDNA3. Override with SLO didn't work. Any chance this gets FSR4 support?
@6ty7er If it's something you absolutely need, you could roll back your Linux kernel to an LTS version with kernel 7.1 or earlier, before they changed something that is contributing to this bug. Or maybe even kernel 6 that is used in Debian.
As for me, I'm an armchair programmer who compiled this solution for people to have an easy way to play without doing anything complicated, and to prove the LLM fix works (and to have people help with finding bugs if it doesn't). The best solution would be to have this fix implemented upstream, or better yet - one made by a knowledgeable developer.
I'm also not skilled or knowledgeable enough to include additions without a significant time investment.
https://github.com/Jpokul/prototype_SM2_proton_fix_patch14-15 is a build compiled from https://github.com/ValveSoftware/Proton at commit adea6cb.
From what I gather, it should include FSR4 support, but I don't know how to verify it or if it works with SM2. You may try using the launch option PROTON_FSR4_UPGRADE=1; if it works for you, great. If it doesn't, I don't know how to do it. I checked SM2, and it doesn't clearly communicate which FSR it's using.
If somebody doesn't trust my compilation or wants functionality outside what the aforementioned Proton offers, compiling it yourself using the fix written in https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-5903294489 should do the trick. It's highly encouraged to verify the code yourself first.
As for my build, I also used another fix: https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-5943056744, but that one isn't required.
EDIT: After some investigating, it seems FSR4 doesn't work on Proton Experimental with Radeon 9000 series. In that case, it won't work with the prototype fix either.
@defaultuser321 Thanks, the log helps. This is a different problem from the crash in this issue:
code=c0000005 at Retail.exe+0x2158FEE on the resFILE_LOADER thread). Your log has none, only the usual debug-print and thread-naming exceptions. So the patches in the prototype have nothing to fix here.NtGdiDdDDIQueryStatistics) every frame, about 60 times a second, with no gap over 2 s after the first minute. At 21:00:02 it rescanned HID devices: the two hid_joystick_device_try_open device usage 000c:0001 / ff00:0001 not implemented! lines are dinput skipping two devices that aren't gamepads, the same two it skipped at startup. The thread never logged anything again.err:sync ... wait timed out lines (Wine prints one after 5 s on a critical section) and no vkd3d-proton errors.In your log the game scans for input devices twice at startup and then only once more, at 21:00:02, two seconds after the top of the hour. Games usually rescan when Windows reports a device change, so something probably happened on your system at 21:00: a scheduled job (backup, snapshot, updater), or a controller, headset, dongle or other USB/Bluetooth device connecting, disconnecting or waking up. The main thread got stuck in that rescan or in whatever the game did right after it.
I don't see how either patch could cause this. The only new waiting in the ntdll change happens when a timed wait times out at the same moment a wake arrives: it then takes that wake, which is already on its way, instead of leaving it pending. The mutex change only matters when a thread dies while owning a mutex, or when a mutex handle is closed while another thread of the same process is still waiting on it, and nothing like that happens in the rescan. Testing without the patches is the way to be sure, though.
What would narrow it down:
report_* folders are always empty (the game makes one at every launch; mine are empty too). A crash leaves crash_data.zip directly in reports/, and its date would tell us whether you ever had the crash from this issue.sudo if it only shows your own user's messages):journalctl --since "2026-10-06 20:59:50" --until "2026-10-06 21:00:40" -o short-precise > ~/sm2-journal.txt
It covers USB/Bluetooth, timers and cron jobs, and amdgpu if the GPU had hung. Look it over for anything private before attaching it./proc and attaches nothing to the game, so it's fine with EAC:pid=$(pgrep -n -f 'Space Marine 2 - Retai[l]')
top -H -b -n 2 -d 2 -w 200 -p "$pid" > ~/sm2-freeze-top.txt
ps -L -o tid,stat,wchan:32,comm -p "$pid" > ~/sm2-freeze-threads.txt
for p in $(pgrep -f 'winedevice.ex[e]'); do ps -L -o tid,stat,wchan:32,comm -p "$p"; done >> ~/sm2-freeze-threads.txt
If you can, also use PROTON_LOG=+hid,+mountmgr %command% instead of PROTON_LOG=1 for that session. It adds HID device opens and drive changes to the log. With a controller connected the log gets much bigger, but it compresses well.@jegglest
1. What did you get before the prototype? Was it this same freeze, or the "Unhandled exception happened" window? The report_* folders are always empty (the game makes one at every launch; mine are empty too). A crash leaves crash_data.zip directly in reports/, and its date would tell us whether you ever had the crash from this issue.
2. Do your freezes line up with anything? The top of the hour, a controller or headset turning on/off or going to sleep, a USB device, a monitor switching off or changing input?3. The system journal for that minute, if it's still there (add sudo if it only shows your own user's messages): journalctl --since "2026-10-06 20:59:50" --until "2026-10-06 21:00:40" -o short-precise > ~/sm2-journal.txt4. A session or two on stock Proton Experimental. If it freezes the same way there, the patches aren't involved.5. If it freezes again, run this in a terminal before you force-quit. It only reads /proc and attaches nothing to the game, so it's fine with EAC: pid=$(pgrep -n -f 'Space Marine 2 - Retai[l]') top -H -b -n 2 -d 2 -w 200 -p "$pid" > ~/sm2-freeze-top.txt ps -L -o tid,stat,wchan:32,comm -p "$pid" > ~/sm2-freeze-threads.txt for p in $(pgrep -f 'winedevice.ex[e]'); do ps -L -o tid,stat,wchan:32,comm -p "$p"; done >> ~/sm2-freeze-threads.txt If you can, also use PROTON_LOG=+hid,+mountmgr %command% instead of PROTON_LOG=1 for that session. It adds HID device opens and drive changes to the log. With a controller connected the log gets much bigger, but it compresses well.EDIT: The freeze landed within a second of the Timeshift cron job at exactly 21:00:01. So I was wrong with 19:00 time of Timeshift backup. I am no expert but could it be some bug in regard to cron itself? And if it is cron bug, why is everything except Space Marine 2 working without any issue?
Well, I disabled cron for the test and set Space Marine 2 to use latest Proton CachyOS V3 and game is running buttery smooth for 4 hours now. Looks like for some reason cron or cron related action was the cause of my issues. Strangely game is now working even without the fix you created.
Anyway, thank you for helping me find out the problem.
Well, I disabled cron for the test and set Space Marine 2 to use latest Proton CachyOS V3 and game is running buttery smooth for 4 hours now. Looks like for some reason cron or cron related action was the cause of my issues. Strangely game is now working even without the fix you created.
Anyway, thank you for helping me find out the problem.
Have you recreated your proton prefix before switching to proton-cachyos again?
How do you disabled Cron?
@JMarcosHP
Well, I disabled cron for the test and set Space Marine 2 to use latest Proton CachyOS V3 and game is running buttery smooth for 4 hours now. Looks like for some reason cron or cron related action was the cause of my issues. Strangely game is now working even without the fix you created.
Anyway, thank you for helping me find out the problem.Have you recreated your proton prefix before switching to proton-cachyos again?
How do you disabled Cron?
"sudo systemctl stop cron
systemctl is-active cron"
This will just pause cron and verify if it is inactive (effective until restart of the system or manual activation)
And yes, I recreated my original Proton prefix I uses some time ago.
"ENABLE_LAYER_MESA_ANTI_LAG=1 PROTON_FSR4_UPGRADE=1 PROTON_MLFG_UPGRADE=1 mesa_glthread=true WINE_VK_USE_SYNC2=1 WINE_SYNC_USE_FUTEX_WAITV=1 %command% -skip-launcher"
But of course, running the game for several hours without the crash does not necessarily mean the problem with the game is not present. It simply might occur less often. The time will tell.
It's going to take time for these issues to be addressed upstream, we need more people testing the patches with other games, not just space marine 2.
I've forked proton experimental https://github.com/jegglest/proton-je and submitted a PR to add it to ProtonPlus.
@6ty7er If it's something you absolutely need, you could roll back your Linux kernel to an LTS version with kernel 7.1 or earlier, before they changed something that is contributing to this bug. Or maybe even kernel 6 that is used in Debian.
Yes, this is something I need. I waited since 7800XT release for FSR4. FSR3 is really ugly.
As for me, I'm an armchair programmer who compiled this solution for people to have an easy way to play without doing anything complicated, and to prove the LLM fix works (and to have people help with finding bugs if it doesn't). The best solution would be to have this fix implemented upstream, or better yet - one made by a knowledgeable developer.
I really appreciate this, but I'm asking myself why there is no FSR4? If you don't know the difference, you should look it up.
@jegglest
It's going to take time for these issues to be addressed upstream, we need more people testing the patches with other games, not just space marine 2.
I've forked proton experimental https://github.com/jegglest/proton-je and submitted a PR to add it to ProtonPlus.
Let me know if you need any help with testing. When I got time I can help with pretty much anything. Just please bear in mind that I have no programming background at all, so any complex request might need more precise explanation.
From what I read about FSR4 - it is included in the proton experimental, but there is a bug that fails to properly enable FSR 4 on RDNA 4 (Radeon 9000) hardware or certain games because the bundled FSR 4 dynamic-link library (amdxcffx64.dll) restricts execution strictly to RDNA 3 GPUs (Radeon 7000), causing it to fall back to FSR 3.
@defaultuser321 yes, that would be great! I'm quite confident the patches fix space marine 2. What I'm most interested in is if anyone can find a game that the patches break.
proton-je now has FSR 4 support. @Jpokul it was harder than what you're describing but I mainly cherry picked patches that already exist. Hopefully, that will make proton-je more tolerable to use for testing the fixes.
When it is added to ProtonPlus it should be easier for everyone to install it and keep it updated. In the mean time:
@jegglest I can also help with testing. I added your patches to proton GE lastest, compiled, and ran briefly with Control Resonance and it did not cure my crash on an rtx3080 that pyroveil fixes which most likely means it won't help Alan Wake 2 either. I have some free time coming up so I'll confirm I have the same error or a similar one as Space Marine 2, and provide more details to see if the patch even applies. Could have sworn I had the same Xid109 plus waiting for sephamore error, but I'll do my due diligence and report back. Might be entirely separate.
@Erfboom thanks! Yeah, any feedback on any games is great, even if the feedback is, no perceivable effect.
Just wanted to say Thank you, the fix absolutely fixed the SM2 crashing bug for me. You guys are doing god's work and for the emperor! :)
There is a new build: proton-je-11.0-20261001-3, the patches had a regression which showed up when I played Foundry for a little bit. Grab the new build, or update your own locally patched proton: https://github.com/jegglest/proton-je#installing-a-build
Why this release: proton-je-11.0-20261001-1 and -2 abort any game once it has about 3300 handles open at once and waits on one of the higher ones. Patch 5 made the in-process sync cache entry 20 bytes, the cache mapped its 64K blocks at the entries' exact size, 65520 bytes, and Wine's anon_mmap_alloc() asserts that its size is a multiple of the page size: the game disappears or freezes, and the only trace is one line in Steam's console log, virtual.c:408: anon_mmap_alloc: Assertion `!(size & host_page_mask)' failed. Found with Foundry during an autosave. The cache now maps whole 64K blocks (details); nothing else changed since -2. Please replace -1 and -2 with this build.
@jegglest confirming, using proton-je, game did not crash once in the last 14 hours
proton experimentalx36 2026-10ge-proton11-1x1 2026-10proton 10.0x1 2026-10proton 3.1x1 2026-09proton hotfixx4 2026-09proton 11.0-2x8 2026-09proton 11.0-2cx1 2026-09proton 9.0-4x2 2026-09ge-proton10-34x1 2026-09ge-proton11-5x1 2026-09ge-proton11-6x1 2026-09ge-proton10-29x1 2026-02ge-proton10-28x1 2026-01proton 9.0x1 2026-01ge-proton10-25x1 2025-12PROTON_FSR4_UPGRADE=1x2 2026-10PROTON_MLFG_UPGRADE=1x1 2026-10WINE_SYNC_USE_FUTEX_WAITV=1x1 2026-10WINE_VK_USE_SYNC2=1x1 2026-10PROTON_LOG=1x10 2026-10PROTON_LOG=+hid,+mountmgrx2 2026-10PROTON_NO_NTSYNC=1x2 2026-10WINE_STALE_ALERT_FIX=0x1 2026-09VKD3D_CONFIG=no_upload_hvvx6 2026-09PROTON_DISABLE_NVAPI=1x1 2026-09VKD3D_CONFIG=faultx1 2026-09VKD3D_CONFIG=log_memory_budgetx1 2026-09ENABLE_VKBASALT=1x1 2026-09PROTON_DISCORD_BRIDGE=1x1 2026-09PROTON_FSR4_RDNA3_UPGRADE=1x1 2026-09ENABLE_LAYER_MESA_ANTI_LAG=1 PROTON_FSR4_UPGRADE=1 PROTON_MLFG_UPGRADE=1 mesa_glthread=true WINE_VK_USE_SYNC2=1 WINE_SYNC_USE_FUTEX_WAITV=1 %command% -skip-launcherx1 2026-10ENABLE_VKBASALT=1 PROTON_FSR4_RDNA3_UPGRADE=1 PROTON_DISCORD_BRIDGE=1 LOW_LATENCY_LAYER=1 PROTON_LOG=1 gamemoderun %command%x1 2026-09gamescope -W 3840 -H 2160 -r 60 -f -- %command%x1 2026-06gamescope -W 3840 -H 2160 -r 90 -f -- %command%x1 2026-06gamescope -W 3840 -H 2160 -f -- %command%x2 2026-06PROTON_USE_NTSYNC=1 gamemoderun __GL_SHARPEN_ENABLE=1 __GL_SHARPEN_VALUE=100 PROTON_HIDE_NVIDIA_GPU=0 PROTON_ENABLE_NVAPI=1 PROTON_NVIDIA_LIBS=1 %command%x1 2026-04PROTON_SET_GAME_DRIVE=1 %command%x2 2026-03PYROVEIL=1 PYROVEIL_CONFIG=~/pyroveil/hacks/space-marine-2-nv/pyroveil.json DXVK_ASYNC=1 %command%x1 2026-03VKD3D_CONFIG=no_upload_hvv %command%x3 2024-11SteamDeck=1 %command%x1 2024-10SteamDeck=1 gamescope -h 1440 -r 165 --force-grab-cursor -- %command%x2 2024-10amdxcffx64.dllx1 2026-10ntdll.dllx4 2026-10libtcmalloc_minimal.dllx1 2026-09nvapi64.dllx1 2026-09kernel32.dllx2 2026-090xc0000005x2 2026-100x887a0005x1 2026-09
Compatibility Report
System Information
I confirm:
steam-2183900.zip
Symptoms
Game launches fine. When new game is started and the intro cinematic runs (which seems to double as map loading), a message pops up saying "You have failed to connect to the game" in always the same spot. After confirming the popup the game displays a black window with a "Signed in as [USER]" message in left top corner and doesn't respond anymore.
Possibly anti-cheat related? Running
SteamDeck=1doesn't help.Reproduction
Start new game, watch intro cinematic, always get disconnected.