From 9ec97f9d33399eeb9fadb284af63f5d2753503f4 Mon Sep 17 00:00:00 2001 From: sanasol Date: Tue, 27 Jan 2026 19:40:42 +0100 Subject: [PATCH] fix: Steam Deck/Ubuntu crash - use system libzstd.so The bundled libzstd.so is incompatible with glibc 2.41's stricter heap validation, causing "free(): invalid pointer" crashes. Solution: Automatically replace bundled libzstd.so with system version on Linux. The launcher detects and symlinks to /usr/lib/libzstd.so.1. - Auto-detect system libzstd at common paths (Arch, Debian, Fedora) - Backup bundled version as libzstd.so.bundled - Create symlink to system version - Add HYTALE_NO_LIBZSTD_FIX=1 to disable if needed Co-Authored-By: Claude Opus 4.5 --- backend/managers/gameLauncher.js | 49 ++++++++++ docs/STEAMDECK_CRASH_INVESTIGATION.md | 123 ++++++++++++++++++++++++++ docs/STEAMDECK_DEBUG_COMMANDS.md | 65 ++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 docs/STEAMDECK_CRASH_INVESTIGATION.md create mode 100644 docs/STEAMDECK_DEBUG_COMMANDS.md diff --git a/backend/managers/gameLauncher.js b/backend/managers/gameLauncher.js index fddfa7f..0ac187d 100644 --- a/backend/managers/gameLauncher.js +++ b/backend/managers/gameLauncher.js @@ -285,6 +285,55 @@ exec "$REAL_JAVA" "\${ARGS[@]}" const gpuEnv = setupGpuEnvironment(gpuPreference); Object.assign(env, gpuEnv); + // Linux: Replace bundled libzstd.so with system version to fix glibc 2.41+ crash + // The bundled libzstd causes "free(): invalid pointer" on Steam Deck / Ubuntu LTS + if (process.platform === 'linux' && process.env.HYTALE_NO_LIBZSTD_FIX !== '1') { + const clientDir = path.dirname(clientPath); + const bundledLibzstd = path.join(clientDir, 'libzstd.so'); + const backupLibzstd = path.join(clientDir, 'libzstd.so.bundled'); + + // Common system libzstd paths + const systemLibzstdPaths = [ + '/usr/lib/libzstd.so.1', // Arch Linux, Steam Deck + '/usr/lib/x86_64-linux-gnu/libzstd.so.1', // Debian/Ubuntu + '/usr/lib64/libzstd.so.1' // Fedora/RHEL + ]; + + let systemLibzstd = null; + for (const p of systemLibzstdPaths) { + if (fs.existsSync(p)) { + systemLibzstd = p; + break; + } + } + + if (systemLibzstd && fs.existsSync(bundledLibzstd)) { + try { + const stats = fs.lstatSync(bundledLibzstd); + + // Only replace if it's not already a symlink to system version + if (!stats.isSymbolicLink()) { + // Backup bundled version + if (!fs.existsSync(backupLibzstd)) { + fs.renameSync(bundledLibzstd, backupLibzstd); + console.log(`Linux: Backed up bundled libzstd.so`); + } else { + fs.unlinkSync(bundledLibzstd); + } + + // Create symlink to system version + fs.symlinkSync(systemLibzstd, bundledLibzstd); + console.log(`Linux: Linked libzstd.so to system version (${systemLibzstd}) for glibc 2.41+ compatibility`); + } else { + const linkTarget = fs.readlinkSync(bundledLibzstd); + console.log(`Linux: libzstd.so already linked to ${linkTarget}`); + } + } catch (libzstdError) { + console.warn(`Linux: Could not replace libzstd.so: ${libzstdError.message}`); + } + } + } + try { let spawnOptions = { stdio: ['ignore', 'pipe', 'pipe'], diff --git a/docs/STEAMDECK_CRASH_INVESTIGATION.md b/docs/STEAMDECK_CRASH_INVESTIGATION.md new file mode 100644 index 0000000..a7c95c9 --- /dev/null +++ b/docs/STEAMDECK_CRASH_INVESTIGATION.md @@ -0,0 +1,123 @@ +# Steam Deck / Ubuntu LTS Crash Investigation + +## Status: SOLVED + +**Last updated:** 2026-01-27 + +**Solution:** Replace bundled `libzstd.so` with system version. + +--- + +## Problem Summary + +The Hytale F2P launcher's client patcher causes crashes on Steam Deck and Ubuntu LTS with the error: +``` +free(): invalid pointer +``` +or +``` +SIGSEGV (Segmentation fault) +``` + +The crash occurs after successful authentication, specifically right after "Finished handling RequiredAssets". + +**Affected Systems:** +- Steam Deck (glibc 2.41) +- Ubuntu LTS + +**Working Systems:** +- macOS +- Windows +- Older Arch Linux (glibc < 2.41) + +--- + +## Root Cause + +The **bundled `libzstd.so`** in the game client is incompatible with glibc 2.41's stricter heap validation. When the game decompresses assets using this library, it triggers heap corruption detected by glibc 2.41. + +The crash occurs in `libzstd.so` during `free()` after "Finished handling RequiredAssets" (asset decompression). + +--- + +## Solution + +Replace the bundled `libzstd.so` with the system's `libzstd.so.1`. + +### Automatic (Launcher) + +The launcher automatically detects and replaces `libzstd.so` on Linux systems. No manual action needed. + +### Manual + +```bash +cd ~/.hytalef2p/release/package/game/latest/Client + +# Backup bundled version +mv libzstd.so libzstd.so.bundled + +# Link to system version +# Steam Deck / Arch Linux: +ln -s /usr/lib/libzstd.so.1 libzstd.so + +# Debian / Ubuntu: +ln -s /usr/lib/x86_64-linux-gnu/libzstd.so.1 libzstd.so + +# Fedora / RHEL: +ln -s /usr/lib64/libzstd.so.1 libzstd.so +``` + +### Restore Original + +```bash +cd ~/.hytalef2p/release/package/game/latest/Client +rm libzstd.so +mv libzstd.so.bundled libzstd.so +``` + +--- + +## Why This Works + +1. The bundled `libzstd.so` was likely compiled with different allocator settings or an older toolchain +2. glibc 2.41 has stricter heap validation that catches invalid memory operations +3. The system `libzstd.so.1` is compiled with the system's glibc and uses compatible memory allocation patterns +4. By using the system library, we avoid the incompatibility entirely + +--- + +## Previous Investigation (for reference) + +### What Was Tried Before Finding Solution + +| Approach | Result | +|----------|--------| +| jemalloc allocator | Worked ~30% of time, not stable | +| GLIBC_TUNABLES | No effect | +| taskset (CPU pinning) | Single core too slow | +| nice/chrt (scheduling) | No effect | +| Various patching approaches | All crashed | + +### Key Insight + +The crash was in `libzstd.so`, not in our patched code. The patching just changed timing enough to expose the libzstd incompatibility more frequently. + +--- + +## GDB Stack Trace (Historical) + +``` +#0 0x00007ffff7d3f5a4 in ?? () from /usr/lib/libc.so.6 +#1 raise () from /usr/lib/libc.so.6 +#2 abort () from /usr/lib/libc.so.6 +#3-#4 ?? () from /usr/lib/libc.so.6 +#5 free () from /usr/lib/libc.so.6 +#6 ?? () from libzstd.so <-- CRASH POINT (bundled library) +#7-#24 HytaleClient code (asset decompression) +``` + +--- + +## Branch + +`fix/steamdeck-libzstd` diff --git a/docs/STEAMDECK_DEBUG_COMMANDS.md b/docs/STEAMDECK_DEBUG_COMMANDS.md new file mode 100644 index 0000000..a727301 --- /dev/null +++ b/docs/STEAMDECK_DEBUG_COMMANDS.md @@ -0,0 +1,65 @@ +# Steam Deck / Linux Crash Fix + +## SOLUTION: Use system libzstd + +The crash is caused by the bundled `libzstd.so` being incompatible with glibc 2.41's stricter heap validation. + +### Automatic Fix + +The launcher automatically replaces `libzstd.so` with the system version. No manual action needed. + +### Manual Fix + +```bash +cd ~/.hytalef2p/release/package/game/latest/Client + +# Backup and replace +mv libzstd.so libzstd.so.bundled +ln -s /usr/lib/libzstd.so.1 libzstd.so +``` + +### Restore Original + +```bash +cd ~/.hytalef2p/release/package/game/latest/Client +rm libzstd.so +mv libzstd.so.bundled libzstd.so +``` + +--- + +## Debug Commands (for troubleshooting) + +### Check libzstd Status + +```bash +# Check if symlinked +ls -la ~/.hytalef2p/release/package/game/latest/Client/libzstd.so + +# Find system libzstd +find /usr/lib -name "libzstd.so*" +``` + +### Binary Validation + +```bash +file ~/.hytalef2p/release/package/game/latest/Client/HytaleClient +ldd ~/.hytalef2p/release/package/game/latest/Client/HytaleClient +``` + +### Restore Client Binary + +```bash +cd ~/.hytalef2p/release/package/game/latest/Client +cp HytaleClient.original HytaleClient +rm -f HytaleClient.patched_custom +``` + +--- + +## Environment Variables + +| Variable | Description | Example | +|----------|-------------|---------| +| `HYTALE_AUTH_DOMAIN` | Custom auth domain | `auth.sanasol.ws` | +| `HYTALE_NO_LIBZSTD_FIX` | Disable libzstd replacement | `1` |