protonscr

Steam app 2278520 (Enshrouded dedicated server) via umu-launcher: steamclient64.dll DllMain execute fault with GE-Proton 11-9 / Proton Experimental 11.0-20261014 (wine-11.0)

protonclosed
ValveSoftware/Proton#10282 · opened 2026-10-18 by goetterbote2342 · updated 2026-10-18 · 1 comments · github
Ggoetterbote2342 2026-10-18 github

Report produced while fixing a self-hosted Enshrouded dedicated-server deployment (ensmanager.sh). Everything quoted below was observed on the machine described in §2; the same setup on Debian x86_64 shows the same abort.

Compatibility report fields

  • Name of the software with compatibility issues: Enshrouded dedicated server (app 2278520; run headless through umu-launcher, not launched by the Steam client)
  • Steam AppID: 2278520
  • Proton version: GE-Proton 11-9 and Proton Experimental 11.0-20261014 (also reproduced with proton-cachyos-slr 1:11.0.20261014, i.e. bleeding-edge wine 2026-10-16)
  • Distro/kernel: CachyOS x86_64, 7.2.9-2-cachyos (original report: Debian x86_64)
  • umu-launcher 1.4.4, Steam Linux Runtime steamrt4
  • Control: same prefix/exe/DLL under system wine-11.20 works (see §5)

Upstream report — Proton/umu: Windows dedicated server aborts because Valve's steamclient64.dll takes an execute fault in DllMain under the shipped Wine (11.0-based), while Wine's development branch (11.20) runs the very same binary

Status: ready to file. No account/credentials were available on the machine where this was
written, so it was not posted yet — see "Where to file" at the bottom for the exact
trackers, titles and which sections to paste where.


1. Summary

  • Subject: Enshrouded dedicated server, Steam app 2278520 (Windows x86_64), started with
    umu-launcher 1.4.4 + GE-Proton 11-9 (bundles wine 11.0 Staging).

  • Symptom: the server starts, then aborts within ~200 ms of its own start:
    [steam] Failed to initialize Steamworks system...Generic Error,
    Message from Steam: Failed to load module 'C:\Program Files (x86)\Steam\steamclient64.dll',
    [app] Failed to create Steamworks. → process exits, so it never reaches
    [Session] 'HostOnline' (up)! and never binds query port 15637.

  • Cause (measured): Wine's loader releases Valve's steamclient64.dll again because the DLL's
    DllMain (PROCESS_ATTACH) takes an access violation:

    00f0:Call KERNEL32.VirtualProtect(<base>+0x1930000, 0x100, PAGE_READWRITE)
    00f0:Call KERNEL32.VirtualProtect(<base>+0x1930000, 0x100, PAGE_READONLY)
    00f0:exception c0000005 in PE entry point (module=...steamclient64.dll, reason=PROCESS_ATTACH, res=0)
    00f0:Ret  PE DLL (... L"steamclient64.dll", reason=PROCESS_ATTACH) retval=0
    00f0:free_modref Unloaded module ... steamclient64.dll : native
    

    With Wine's default debug channels the same run prints
    wine: Unhandled page fault on execute access to 00006FFFFB24DC74.

    <base>+0x1930000 is the DLL's .fptable section (SizeOfImage 0x197D000, ImageBase
    0x138000000, .text is CODE, .fptable at 0x1930000 size 0x100 is DATA/RW); the fault
    address is inside the DLL's own .text — i.e. the DLL patches code and then jumps into it,
    and the page is not executable any more.

  • Control: the same prefix, the same exe and the same steamclient64.dll (sha256
    caba4826aa3501039d095aee1843a6bfb270fb43a3ab4455b2d6733223579fee, byte-identical to the
    Steamworks redistributable from app 1007) run fine under wine-11.20 (Wine development branch):
    the module stays loaded (build_module Loaded ... steamclient64.dll : native, no free_modref),
    Steamworks initialises offline ([API loaded no]) and the server comes up
    ([online] Server connected to Steam successfully, [Session] 'HostOnline' (up)!, UDP 15637 listening).

  • Scope of the problem: every Proton/Wine build we could obtain is based on wine 11.0:
    GE-Proton 11-9 (newest GE release, 2026-10-14), proton-cachyos-slr 1:11.0.20261014
    (rebased on Valve's experimental-wine-bleeding-edge-11.0-453249-20261016, published 2026-10-17)
    and Valve's Proton Experimental 11.0-20261014 — all three fail (the CachyOS one was tested
    directly, the other two are the same wine base). So currently no released Proton can run this
    server; the fix exists in Wine's development branch only.

2. Environment

Host (where reproduced) CachyOS x86_64, kernel 7.2.9-2-cachyos
umu-launcher 1.4.4 (zipapp: umu/umu/umu-run), runtime steamrt4
Proton GE-Proton11-9 (newest GE release 2026-10-14); proton/GE-Proton11-9/version → GE-Proton11-9; wine: wine-11.0 (Staging) (files/lib/wine/x86_64-unix/ntdll.so)
Prefix proton-prefix (created by Proton for GE-Proton11-9: "Upgrading prefix from None to GE-Proton11-9")
Server Steam app 2278520 (anonymous SteamCMD download, 7.5 GB, x86_64), started from its own directory
Control engine system wine-11.20 (Wine development release, same prefix)
Also tested proton-cachyos-slr 1:11.0.20261014-1 (/usr/share/steam/compatibilitytools.d/…, wine 11.0 (CachyOS), rebased on ValveSoftware/wine@experimental-wine-bleeding-edge-11.0-453249-20261016-pf413b3-wc53678a-d6689ca-v0bb64c) → same failure

The failure was first hit while fixing a Debian x86_64 deployment of the same setup (ensmanager.sh,
same umu/GE-Proton versions); the machine above is where it was reproduced and traced.

3. Reproduction

3.1 Minimal (umu + GE-Proton)

# once: server files + GE-Proton + umu (no Steam client involved; anonymous SteamCMD is enough)
steamcmd +@sSteamCmdForcePlatformType windows +@sSteamCmdForcePlatformBitness 64 \
         +force_install_dir "$PWD/enshrouded-server" +login anonymous +app_update 2278520 validate +quit
# GE-Proton11-9 (x86_64 tarball) -> ./proton/GE-Proton11-9, umu zipapp -> ./umu/umu/umu-run

cd enshrouded-server
WIN_EXE="Z:${PWD//\//\\}\\enshrouded_server.exe"     # unix path -> Windows path for Proton
env WINEPREFIX="$PWD/../proton-prefix" GAMEID=umu-enshrouded-server STORE=none \
    PROTONPATH="$PWD/../proton/GE-Proton" PROTON_USE_XALIA=0 \
    WINEDLLOVERRIDES="lsteamclient=d;steamclient64=n;steamclient=n" \
    "$PWD/../umu/umu/umu-run" "$WIN_EXE"

Notes that matter for the repro:

  • The executable must be passed as a Windows path (Z:…). With a unix path, Proton wraps it in
    its umu.exe shim and the server deadlocks before it even writes its log (see §6, secondary finding).
  • The prefix registry advertises HKCU\Software\Valve\Steam\ActiveProcess\SteamClientDll64 = C:\Program Files (x86)\Steam\steamclient64.dll, but a prefix created without a Steam client does
    not contain that file. Copy the DLL the server ships into place (otherwise the load fails one step
    earlier, for a missing file):
    mkdir -p "proton-prefix/drive_c/Program Files (x86)/Steam" && cp enshrouded-server/steamclient64.dll "proton-prefix/drive_c/Program Files (x86)/Steam/"

3.2 With logs

env … WINEDEBUG=+loaddll,+relay "$PWD/../umu/umu/umu-run" 'Z:\…\enshrouded_server.exe' > /tmp/run.log 2>&1
# then look for:  grep -an 'steamclient64\|exception c0000005\|free_modref\|Failed to load module' /tmp/run.log

Server's own log appears in enshrouded-server/logs/enshrouded_server.log.

4. Observed evidence (verbatim)

Server log (logs/enshrouded_server.log):

[I 00:00:00,026] [app] start creation step Init
[I 00:00:00,026] [app] start creation step Init_Steamworks
[E 00:00:00,078] [steam] Failed to initialize Steamworks system...Generic Error
[E 00:00:00,078] [steam] Message from Steam: Failed to load module 'C:\Program Files (x86)\Steam\steamclient64.dll'
[E 00:00:00,078] [app] Failed to create Steamworks.
[I 00:00:00,094] [app] start destruction step Init

WINEDEBUG=+loaddll,+relay (the module is loaded, its DllMain runs, then the loader releases it):

00f0:Call KERNEL32.InitializeCriticalSectionEx(...)   (x9)
00f0:Call KERNEL32.GetProcessHeap()
00f0:Call KERNEL32.LoadLibraryExW(... L"api-ms-win-core-fibers-l1-1-2", ...)
00f0:Call KERNEL32.GetProcAddress(..., "FlsGetValue2")   -> retval=00000000
00f0:Call KERNEL32.VirtualProtect(<base>+0x1930000, 0x100, PAGE_READWRITE)
00f0:Call KERNEL32.VirtualProtect(<base>+0x1930000, 0x100, PAGE_READONLY)
00f0:Call KERNEL32.FlsAlloc(...)
00f0:Call KERNEL32.GetLastError()   (x4)
00f0:exception c0000005 in PE entry point (module=00006FFFFA2E0000 L"steamclient64.dll", reason=PROCESS_ATTACH, res=0)
00f0:free_modref Unloaded module L"C:\Program Files (x86)\Steam\steamclient64.dll" : native

With default debug channels:

wine: Unhandled page fault on execute access to 00006FFFFB24DC74

(The DLL is loaded at a Wine-chosen base around 0x6FFFFA2E0000; 0x6FFFFB24DC74 - base = 0xF6DC74 is inside SizeOfImage 0x197D000, i.e. in .text. The VirtualProtect pair targets
.fptable at +0x1930000, size 0x100.)

5. Control: wine-11.20 with the identical inputs

# same prefix, same exe, same steamclient64.dll — only the Wine build differs
cd enshrouded-server && WINEPREFIX="$PWD/../proton-prefix" wine enshrouded_server.exe

Result: build_module Loaded ... enshrouded-server\steamclient64.dll : native — and no
free_modref; the server continues:

[I 00:00:02,951] [online] Server connected to Steam successfully
[I 00:00:03,198] [online] Server SteamId: 90295163380246541
[I 00:00:03,207] [Session] 'HostOnline' (up)!
$ ss -lntup | grep 15637
udp UNCONN 0 0 0.0.0.0:15637 …

The client DLL's own call sequence (extracted from both +relay traces, filtered to calls made
from inside the module) is identical up to the fault — same FlsGetValue2 → NULL, same
VirtualProtect pair, same GetLastError probes. wine-11.20 continues (more
InitializeCriticalSectionEx), wine-11.0 faults. So the difference is Wine's handling, not the
DLL's logic.

6. Secondary finding (same class of environment, worth fixing too)

umu-run is normally called with a unix path. In that case GE-Proton's proton script
(proton:2857) wraps the executable in its umu.exe shim
(Proton: Executable is a unix path, launching with 'umu.exe'.) and this dedicated server then
deadlocks before writing its log:

  • process state: 1 thread, wchan=ntsync_schedule, 0 CPU;
  • gdb: ioctl → linux_wait_objs → inproc_wait → NtWaitForMultipleObjects → wait_message → wait_message_reply (win32u);
  • WINEDEBUG=+win,+msg ends with NtUserWaitForInputIdle timeout or error and repeated
    msg:send_inter_thread_message hwnd 0x10020 msg 0 (WM_NULL) — the game waits for a reply to a
    message sent to the desktop window owned by the shim, while the shim waits for the child.

Passing the Windows path (Proton logs Executable is inside wine prefix, launching normally)
starts the server directly; that is what §3.1 uses. (Not the main subject of this report, but it is
a real deadlock for any headless server launched through umu with a unix path.)

7. Analysis / what we ruled out

All of the following were tried against GE-Proton 11-9 with the same server and produce the same abort
(or a different abort for a missing file); none of them changes the fault:

  • client DLL next to the exe / in the prefix Steam dir / both (steamclient64.dll + steamclient.dll);
  • registry SteamClientDll / SteamClientDll64 removed (Could not determine Steam client install directory.);
  • no client DLL anywhere (Failed to load module …);
  • WINEDLLOVERRIDES lsteamclient=d|n|b, steamclient64=n, steamclient=n;
  • Wine's builtin lsteamclient bridge with STEAM_COMPAT_CLIENT_INSTALL_PATH / LD_LIBRARY_PATH
    pointing at a Steam client library (No SteamClient023 — the bridge needs a running Steam client);
  • WINEDLLPATH=<game dir>, PROTON_VERB=runinprefix, UMU_USE_STEAM=1, GAMEID=umu-2278520,
    SteamAppId/SteamGameId=2278520;
  • sync/loader knobs: PROTON_NO_NTSYNC=1 (fsync), WINENTSYNC=1, WINELOADERNOEXEC=1;
  • setarch -X (READ_IMPLIES_EXEC) and an LD_PRELOAD shim that ORs PROT_EXEC into mprotect
    (the fault survives, i.e. the page does not merely lose its read-only-exec bit);
  • running GE-Proton's own wine binary directly (no umu/container, no Proton environment) — same fault,
    so it is not a Proton environment issue;
  • proton-cachyos-slr (bleeding-edge 2026-10-16 base) — same fault.

Also checked: the Steamworks redistributable (app 1007) ships a byte-identical
steamclient64.dll (sha256 caba4826…), so this is not about the server shipping an odd DLL.

8. Likely upstream cause (inference, marked as such)

Wine's development branch reworked exactly the address-space reservation and page-protection
bookkeeping in dlls/ntdll/unix/virtual.c between the stable 11.0 release (January 2026) and
11.20 (October 2026). The commits present in that window include (dates as of Wine master):

2026-10-14  ntdll: Reserve a top-down area even with a limited 64-bit address space.
2026-10-13  ntdll: Merge the reserved areas and free ranges arrays.
2026-10-12  ntdll: Reserve the entire low 8G on 64-bit.
2026-10-12  ntdll: Add support for blocking some memory ranges from allocation.
2026-10-12  ntdll: Use an array instead of a list for reserved memory areas.
2026-10-12  ntdll: Use calloc to allocate the page protection pointers.
2026-10-07  ntdll: Reserve a larger range for the top-down area.

Valve's Proton wine branch does not contain them: on
ValveSoftware/[email protected]… the newest commits
touching dlls/ntdll/unix/virtual.c are Proton HACK reverts dated 2026-10-14, then commits from
2026-09-15 / 2026-09-05 — the series above is missing. Consistently, GE-Proton 11-9 and
proton-cachyos (that very bleeding-edge tree) fail, while wine-11.20 (contains the series) works.

Caveat: we could not isolate the single fixing commit by bisecting free-running Wine builds; the
statement "this series is what fixes it" is an inference from (a) the behavioural difference
between 11.0 and 11.20 with identical inputs, (b) the fault pattern (page inside a mapped image
becomes non-executable right after the DLL re-protects a neighbouring image page), and (c) the
commit series touching exactly that bookkeeping. Wine developers can confirm/deny this quickly.

9. Impact

Any Windows application under Proton that loads a current Valve Steam client module
(steamclient64.dll, e.g. shipped with a game/server or the Steamworks redistributable) and
self-patches code in DllMain will abort under wine-11.0-based Proton builds. Dedicated servers
started with umu (no Steam client present) are a typical case: Steamworks init cannot succeed, and
some titles treat that as fatal and exit.

10. Suggested actions for the projects

  • Valve / Proton: rebase proton_11.0/bleeding-edge onto the current Wine master (or backport
    the dlls/ntdll/unix/virtual.c reservation/protection series) so that Wine's page-protection
    bookkeeping matches the development branch. After that, no application-side workaround should be
    needed for this case.
  • GE-Proton: pick up the same Wine changes on the next rebase (GE currently tracks Valve's
    bleeding-edge tree, which lacks them) — or document the limitation until then.
  • Proton/umu (secondary): consider not routing dedicated servers through the umu.exe shim when
    the target is a console/headless executable (see §6); the NtUserWaitForInputIdle +
    inter-thread WM_NULL deadlock is reproducible and makes such servers hang before they log anything.
Kkisak-valve maintainer 2026-10-18 github

Hello @goetterbote2342, we're using one issue report per unofficially supported game title, and usually I'd transfer this issue report to #10268, however, your choice to use AI tools has resulted in an excessively wordy mess. Feel free to add a note to that issue report, using your own words and a Proton log from a mainline build for a Proton dev to ponder.

Related threads