Add debug options and jemalloc support for Linux memory issues

Debug env vars for clientPatcher:
- HYTALE_SKIP_SENTRY_PATCH=1 - Skip sentry URL patch (60->26 chars)
- HYTALE_SKIP_SUBDOMAIN_PATCH=1 - Skip subdomain prefix patches

Game launcher Linux options:
- HYTALE_USE_JEMALLOC=1 - Use jemalloc allocator instead of glibc

This helps isolate which patch causes "free(): invalid pointer"
on Steam Deck and Ubuntu LTS.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
sanasol
2026-01-27 02:31:38 +01:00
parent 73f67f2fec
commit c92c5bec3c
2 changed files with 61 additions and 31 deletions

View File

@@ -285,12 +285,30 @@ exec "$REAL_JAVA" "\${ARGS[@]}"
const gpuEnv = setupGpuEnvironment(gpuPreference); const gpuEnv = setupGpuEnvironment(gpuPreference);
Object.assign(env, gpuEnv); Object.assign(env, gpuEnv);
// Disable glibc heap validation on Linux to prevent false positive // Linux memory allocator fixes for "free(): invalid pointer" crashes
// "free(): invalid pointer" crashes on Steam Deck and Ubuntu LTS // on Steam Deck (glibc 2.41) and Ubuntu LTS
// This doesn't hide real bugs - the same binary works on other systems
if (process.platform === 'linux') { if (process.platform === 'linux') {
// Option 1: Disable glibc heap validation
env.MALLOC_CHECK_ = '0'; env.MALLOC_CHECK_ = '0';
console.log('Linux detected: Setting MALLOC_CHECK_=0 to disable glibc heap validation');
// Option 2: Try to use jemalloc if available (more robust allocator)
// User can set HYTALE_USE_JEMALLOC=1 to enable
if (process.env.HYTALE_USE_JEMALLOC === '1') {
const jemalloc = require('fs').existsSync('/usr/lib/libjemalloc.so.2')
? '/usr/lib/libjemalloc.so.2'
: require('fs').existsSync('/usr/lib/x86_64-linux-gnu/libjemalloc.so.2')
? '/usr/lib/x86_64-linux-gnu/libjemalloc.so.2'
: null;
if (jemalloc) {
env.LD_PRELOAD = jemalloc + (env.LD_PRELOAD ? ':' + env.LD_PRELOAD : '');
console.log(`Linux: Using jemalloc allocator (${jemalloc})`);
} else {
console.log('Linux: jemalloc not found, using glibc with MALLOC_CHECK_=0');
}
} else {
console.log('Linux: Using glibc with MALLOC_CHECK_=0 (set HYTALE_USE_JEMALLOC=1 to try jemalloc)');
}
} }
try { try {

View File

@@ -245,6 +245,10 @@ class ClientPatcher {
/** /**
* Apply all domain patches using length-prefixed format * Apply all domain patches using length-prefixed format
* This is the main patching method for variable-length domains * This is the main patching method for variable-length domains
*
* Debug env vars:
* HYTALE_SKIP_SENTRY_PATCH=1 - Skip sentry URL patch (biggest size change)
* HYTALE_SKIP_SUBDOMAIN_PATCH=1 - Skip subdomain prefix patches
*/ */
applyDomainPatches(data, domain, protocol = 'https://') { applyDomainPatches(data, domain, protocol = 'https://') {
let result = Buffer.from(data); let result = Buffer.from(data);
@@ -253,7 +257,10 @@ class ClientPatcher {
console.log(` Patching strategy: ${strategy.description}`); console.log(` Patching strategy: ${strategy.description}`);
// 1. Patch telemetry/sentry URL // 1. Patch telemetry/sentry URL (skip if debugging)
if (process.env.HYTALE_SKIP_SENTRY_PATCH === '1') {
console.log(` Skipping sentry patch (HYTALE_SKIP_SENTRY_PATCH=1)`);
} else {
const oldSentry = 'https://ca900df42fcf57d4dd8401a86ddd7da2@sentry.hytale.com/2'; const oldSentry = 'https://ca900df42fcf57d4dd8401a86ddd7da2@sentry.hytale.com/2';
const newSentry = `${protocol}t@${domain}/2`; const newSentry = `${protocol}t@${domain}/2`;
@@ -268,6 +275,7 @@ class ClientPatcher {
console.log(` Replaced ${sentryResult.count} sentry occurrence(s)`); console.log(` Replaced ${sentryResult.count} sentry occurrence(s)`);
totalCount += sentryResult.count; totalCount += sentryResult.count;
} }
}
// 2. Patch main domain (hytale.com -> mainDomain) // 2. Patch main domain (hytale.com -> mainDomain)
console.log(` Patching domain: ${ORIGINAL_DOMAIN} -> ${strategy.mainDomain}`); console.log(` Patching domain: ${ORIGINAL_DOMAIN} -> ${strategy.mainDomain}`);
@@ -282,7 +290,10 @@ class ClientPatcher {
totalCount += domainResult.count; totalCount += domainResult.count;
} }
// 3. Patch subdomain prefixes // 3. Patch subdomain prefixes (skip if debugging)
if (process.env.HYTALE_SKIP_SUBDOMAIN_PATCH === '1') {
console.log(` Skipping subdomain patches (HYTALE_SKIP_SUBDOMAIN_PATCH=1)`);
} else {
const subdomains = ['https://tools.', 'https://sessions.', 'https://account-data.', 'https://telemetry.']; const subdomains = ['https://tools.', 'https://sessions.', 'https://account-data.', 'https://telemetry.'];
const newSubdomainPrefix = protocol + strategy.subdomainPrefix; const newSubdomainPrefix = protocol + strategy.subdomainPrefix;
@@ -299,6 +310,7 @@ class ClientPatcher {
totalCount += subResult.count; totalCount += subResult.count;
} }
} }
}
return { buffer: result, count: totalCount }; return { buffer: result, count: totalCount };
} }