fix: Steam Deck/Ubuntu crash with jemalloc allocator

Root cause: glibc 2.41 has stricter heap validation that catches a
pre-existing race condition triggered by binary patching.

Changes:
- Add jemalloc auto-detection and usage on Linux
- Add auto-install via pkexec (graphical sudo prompt)
- Clean up clientPatcher.js (remove debug env vars)
- Add null-padding fix for shorter domain replacements
- Document investigation and solution

The launcher now:
1. Auto-detects jemalloc if installed
2. Offers to auto-install if missing (password prompt)
3. Falls back to MALLOC_CHECK_=0 if jemalloc unavailable

Install manually: sudo pacman -S jemalloc (Arch/Steam Deck)
                  sudo apt install libjemalloc2 (Debian/Ubuntu)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
sanasol
2026-01-27 05:01:06 +01:00
parent 9025800820
commit 4c059f0a6b
4 changed files with 492 additions and 459 deletions

View File

@@ -24,6 +24,57 @@ try {
const execAsync = promisify(exec);
/**
* Try to auto-install jemalloc on Linux using pkexec (graphical sudo)
* Returns true if installation was successful
*/
async function tryInstallJemalloc() {
console.log('Linux: Attempting to auto-install jemalloc...');
// Detect package manager and get install command
let installCmd = null;
try {
await execAsync('which pacman');
installCmd = 'pacman -S --noconfirm jemalloc';
} catch (e) {
try {
await execAsync('which apt');
installCmd = 'apt install -y libjemalloc2';
} catch (e2) {
try {
await execAsync('which dnf');
installCmd = 'dnf install -y jemalloc';
} catch (e3) {
console.log('Linux: Could not detect package manager for auto-install');
return false;
}
}
}
// Try pkexec first (graphical sudo), fall back to sudo
const sudoCommands = ['pkexec', 'sudo'];
for (const sudoCmd of sudoCommands) {
try {
await execAsync(`which ${sudoCmd}`);
console.log(`Linux: Installing jemalloc with: ${sudoCmd} ${installCmd}`);
await execAsync(`${sudoCmd} ${installCmd}`, { timeout: 120000 });
console.log('Linux: jemalloc installed successfully');
return true;
} catch (e) {
if (e.killed) {
console.log('Linux: Install timed out');
} else if (e.code === 126 || e.code === 127) {
continue;
} else {
console.log(`Linux: Install failed with ${sudoCmd}: ${e.message}`);
}
}
}
console.log('Linux: Auto-install failed, manual installation required');
return false;
}
// Fetch tokens from the auth server (properly signed with server's Ed25519 key)
async function fetchAuthTokens(uuid, name) {
const authServerUrl = getAuthServerUrl();
@@ -285,6 +336,59 @@ exec "$REAL_JAVA" "\${ARGS[@]}"
const gpuEnv = setupGpuEnvironment(gpuPreference);
Object.assign(env, gpuEnv);
// Linux: Use jemalloc to fix "free(): invalid pointer" crash on glibc 2.41+ (Steam Deck, Ubuntu LTS)
// Root cause: glibc 2.41 has stricter heap validation that catches a pre-existing race condition
if (process.platform === 'linux') {
if (process.env.HYTALE_NO_JEMALLOC !== '1') {
const jemallocPaths = [
'/usr/lib/libjemalloc.so.2', // Arch Linux, Steam Deck
'/usr/lib/x86_64-linux-gnu/libjemalloc.so.2', // Debian/Ubuntu
'/usr/lib64/libjemalloc.so.2', // Fedora/RHEL
'/usr/lib/libjemalloc.so', // Generic fallback
'/usr/lib/x86_64-linux-gnu/libjemalloc.so', // Debian/Ubuntu fallback
'/usr/lib64/libjemalloc.so' // Fedora/RHEL fallback
];
let jemalloc = null;
for (const p of jemallocPaths) {
if (fs.existsSync(p)) {
jemalloc = p;
break;
}
}
if (jemalloc) {
env.LD_PRELOAD = jemalloc + (env.LD_PRELOAD ? ':' + env.LD_PRELOAD : '');
console.log(`Linux: Using jemalloc allocator for stability (${jemalloc})`);
} else {
// Try auto-install
if (process.env.HYTALE_AUTO_INSTALL_JEMALLOC !== '0') {
const installed = await tryInstallJemalloc();
if (installed) {
for (const p of jemallocPaths) {
if (fs.existsSync(p)) {
jemalloc = p;
break;
}
}
if (jemalloc) {
env.LD_PRELOAD = jemalloc + (env.LD_PRELOAD ? ':' + env.LD_PRELOAD : '');
console.log(`Linux: Using jemalloc after auto-install (${jemalloc})`);
}
}
}
if (!jemalloc) {
env.MALLOC_CHECK_ = '0';
console.log('Linux: jemalloc not found - install with: sudo pacman -S jemalloc (Arch) or sudo apt install libjemalloc2 (Debian/Ubuntu)');
console.log('Linux: Using fallback MALLOC_CHECK_=0 (may still crash on glibc 2.41+)');
}
}
} else {
console.log('Linux: jemalloc disabled by HYTALE_NO_JEMALLOC=1');
}
}
try {
let spawnOptions = {
stdio: ['ignore', 'pipe', 'pipe'],