From 55c8f225f2cce71dd3a5d44e990ed76043a61ba6 Mon Sep 17 00:00:00 2001 From: Sais Date: Sat, 25 Jul 2026 02:19:32 -0400 Subject: [PATCH 1/5] Use fixed-width counts in the NetworkId and Unicode packed maps These three AutoDeltaPackedMap specializations wrote their command count as int32 but wrote the baseline count, and read both counts, as size_t. Under ILP32 size_t was 4 bytes so pack and unpack agreed. Under LP64 size_t binds to the 8-byte uint64 Archive overload, so pack writes 4+8 bytes while unpack reads 8+8 and leaves the stream misaligned by 4 bytes for every subsequent key and value. Switch both counts to int32_t, matching the generic internal_pack/ internal_unpack path and the already-converted PlayerQuestData specialization. This also keeps the serialized form identical to the 32-bit server, so data written by either architecture stays readable by the other. --- .../src/shared/AutoDeltaNetworkIdPackedMap.h | 10 +++++----- .../src/shared/NetworkIdAutoDeltaPackedMap.cpp | 10 +++++----- .../src/shared/UnicodeAutoDeltaPackedMap.cpp | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/engine/shared/library/sharedFoundation/src/shared/AutoDeltaNetworkIdPackedMap.h b/engine/shared/library/sharedFoundation/src/shared/AutoDeltaNetworkIdPackedMap.h index 62d073ad..eeed4ede 100755 --- a/engine/shared/library/sharedFoundation/src/shared/AutoDeltaNetworkIdPackedMap.h +++ b/engine/shared/library/sharedFoundation/src/shared/AutoDeltaNetworkIdPackedMap.h @@ -32,8 +32,8 @@ namespace Archive char temp[200]; AutoDeltaMap::Command c; - Archive::put(target, countCharacter(buffer,':')); - Archive::put(target, static_cast(0)); // baselineCommandCount + Archive::put(target, static_cast(countCharacter(buffer,':'))); + Archive::put(target, static_cast(0)); // baselineCommandCount int tempPos = 0; for (std::string::const_iterator i=buffer.begin(); i!=buffer.end(); ++i) @@ -64,8 +64,8 @@ namespace Archive char temp[200]; AutoDeltaMap::Command c; - size_t commandCount; - size_t baselineCommandCount; + int32_t commandCount; + int32_t baselineCommandCount; Archive::get(source, commandCount); Archive::get(source, baselineCommandCount); @@ -76,7 +76,7 @@ namespace Archive } else { - for (size_t i = 0; i < commandCount; ++i) + for (int32_t i = 0; i < commandCount; ++i) { Archive::get(source, c.cmd); Archive::get(source, c.key); diff --git a/engine/shared/library/sharedUtility/src/shared/NetworkIdAutoDeltaPackedMap.cpp b/engine/shared/library/sharedUtility/src/shared/NetworkIdAutoDeltaPackedMap.cpp index d1ba7a66..6e4c58fe 100755 --- a/engine/shared/library/sharedUtility/src/shared/NetworkIdAutoDeltaPackedMap.cpp +++ b/engine/shared/library/sharedUtility/src/shared/NetworkIdAutoDeltaPackedMap.cpp @@ -21,8 +21,8 @@ namespace Archive char value[200]; Command c; - Archive::put(target, countCharacter(buffer,':')); - Archive::put(target, static_cast(0)); // baselineCommandCount + Archive::put(target, static_cast(countCharacter(buffer,':'))); + Archive::put(target, static_cast(0)); // baselineCommandCount int tempPos = 0; for (std::string::const_iterator i=buffer.begin(); i!=buffer.end(); ++i) @@ -52,8 +52,8 @@ namespace Archive char temp[200]; Command c; - size_t commandCount; - size_t baselineCommandCount; + int32_t commandCount; + int32_t baselineCommandCount; Archive::get(source, commandCount); Archive::get(source, baselineCommandCount); @@ -64,7 +64,7 @@ namespace Archive } else { - for (size_t i = 0; i < commandCount; ++i) + for (int32_t i = 0; i < commandCount; ++i) { Archive::get(source, c.cmd); Archive::get(source, c.key); diff --git a/external/ours/library/unicodeArchive/src/shared/UnicodeAutoDeltaPackedMap.cpp b/external/ours/library/unicodeArchive/src/shared/UnicodeAutoDeltaPackedMap.cpp index 8138fdbb..513d0690 100755 --- a/external/ours/library/unicodeArchive/src/shared/UnicodeAutoDeltaPackedMap.cpp +++ b/external/ours/library/unicodeArchive/src/shared/UnicodeAutoDeltaPackedMap.cpp @@ -21,8 +21,8 @@ namespace Archive char temp[200]; Command c; - Archive::put(target, countCharacter(buffer,':')); - Archive::put(target, static_cast(0)); // baselineCommandCount + Archive::put(target, static_cast(countCharacter(buffer,':'))); + Archive::put(target, static_cast(0)); // baselineCommandCount int tempPos = 0; for (std::string::const_iterator i=buffer.begin(); i!=buffer.end(); ++i) @@ -55,8 +55,8 @@ namespace Archive char temp[200]; Command c; - size_t commandCount; - size_t baselineCommandCount; + int32_t commandCount; + int32_t baselineCommandCount; Archive::get(source, commandCount); Archive::get(source, baselineCommandCount); @@ -67,7 +67,7 @@ namespace Archive } else { - for (size_t i = 0; i < commandCount; ++i) + for (int32_t i = 0; i < commandCount; ++i) { Archive::get(source, c.cmd); assert(c.cmd == Command::ADD); // only add is valid in unpack From ec3419dbb00c1624090d95ccb7fcbb5d75e2dff7 Mon Sep 17 00:00:00 2001 From: Sais Date: Sat, 25 Jul 2026 02:19:45 -0400 Subject: [PATCH 2/5] Store call stack addresses at pointer width DebugHelp::getCallStack() handed the caller's uint32 buffer straight to backtrace(), which writes void* entries. Under LP64 that wrote 8 bytes per frame into a 4-byte-per-frame array, overrunning every buffer by 2x: Fatal.cpp uint32[68] = 272 bytes, up to 544 written (stack) CallStack uint32[32] = 128 bytes, 208 written (heap) CallStackCollector uint32[26] = 104 bytes, 208 written (heap) Fatal.cpp's formatMessage() backs every WARNING and FATAL, so any warning that captured a stack corrupted memory. Observed as SIGSEGV inside cfree() with si_addr 0x8 after an unrelated warning fired. Capture into a native void* array and widen into a uint64 buffer, which is correct under both ILP32 and LP64, and widen the storage and printing to match. lookupAddress() already took uint64 on linux; win32 now agrees and no longer truncates StackWalk's DWORD64 address to 32 bits. Also fixes CallStackCollector copying only one element instead of the whole call stack, and CRCing only half the buffer. --- .../sharedDebug/src/linux/DebugHelp.cpp | 23 +++++++++++++++++-- .../library/sharedDebug/src/linux/DebugHelp.h | 5 +++- .../sharedDebug/src/shared/CallStack.cpp | 8 +++---- .../sharedDebug/src/shared/CallStack.h | 3 ++- .../src/shared/CallStackCollector.cpp | 16 ++++++------- .../sharedDebug/src/win32/DebugHelp.cpp | 10 ++++---- .../library/sharedDebug/src/win32/DebugHelp.h | 4 ++-- .../sharedFoundation/src/shared/Fatal.cpp | 6 ++--- 8 files changed, 49 insertions(+), 26 deletions(-) diff --git a/engine/shared/library/sharedDebug/src/linux/DebugHelp.cpp b/engine/shared/library/sharedDebug/src/linux/DebugHelp.cpp index e7a2fb7b..0f84b864 100755 --- a/engine/shared/library/sharedDebug/src/linux/DebugHelp.cpp +++ b/engine/shared/library/sharedDebug/src/linux/DebugHelp.cpp @@ -682,11 +682,30 @@ bool DebugHelp::lookupAddress(uint64 address, char *libName, char *fileName, int // ---------------------------------------------------------------------- -void DebugHelp::getCallStack(uint32 *callStack, int sizeOfCallStack) +void DebugHelp::getCallStack(uint64 *callStack, int sizeOfCallStack) { + //-- backtrace() writes sizeOfCallStack void* entries. Handing it the + // caller's buffer directly only works when sizeof(void*) happens to + // equal the element size; under LP64 it wrote 8 bytes per entry into a + // 4-byte-per-entry array and overran the buffer by 2x. Capture into a + // native pointer array and widen instead, which is correct for both + // ILP32 and LP64. + enum { cs_maximumFrameCount = 256 }; + + if (sizeOfCallStack <= 0) + return; + for (int i = 0; i < sizeOfCallStack; ++i) callStack[i] = 0; - IGNORE_RETURN(backtrace(reinterpret_cast(callStack), sizeOfCallStack)); + + if (sizeOfCallStack > static_cast(cs_maximumFrameCount)) + sizeOfCallStack = static_cast(cs_maximumFrameCount); + + void *frames[cs_maximumFrameCount]; + int const frameCount = backtrace(frames, sizeOfCallStack); + + for (int i = 0; i < frameCount; ++i) + callStack[i] = reinterpret_cast(frames[i]); } // ====================================================================== diff --git a/engine/shared/library/sharedDebug/src/linux/DebugHelp.h b/engine/shared/library/sharedDebug/src/linux/DebugHelp.h index e297f8eb..973c07be 100755 --- a/engine/shared/library/sharedDebug/src/linux/DebugHelp.h +++ b/engine/shared/library/sharedDebug/src/linux/DebugHelp.h @@ -19,7 +19,10 @@ public: static void install(); static void remove(); - static void getCallStack(uint32 *callStack, int sizeOfCallStack); + //-- Entries are instruction addresses, so the buffer must be pointer-width + // capable. uint64 matches lookupAddress() below and is wide enough on + // both ILP32 and LP64. + static void getCallStack(uint64 *callStack, int sizeOfCallStack); static bool lookupAddress(uint64 address, char *libName, char *fileName, int fileNameLength, int &line); }; diff --git a/engine/shared/library/sharedDebug/src/shared/CallStack.cpp b/engine/shared/library/sharedDebug/src/shared/CallStack.cpp index 1df90532..2acb5ab9 100755 --- a/engine/shared/library/sharedDebug/src/shared/CallStack.cpp +++ b/engine/shared/library/sharedDebug/src/shared/CallStack.cpp @@ -59,9 +59,9 @@ void CallStack::debugPrint() const for (size_t i = 2; i < CALLSTACK_DEPTH; ++i) { if (DebugHelp::lookupAddress(m_callStack[i], libName, fileName, sizeof(fileName), line)) - DEBUG_REPORT_PRINT(true, (" (0x%08X) %s(%d) : caller %d\n", static_cast(m_callStack[i]), fileName, line, i - 1)); + DEBUG_REPORT_PRINT(true, (" (0x%016llX) %s(%d) : caller %d\n", static_cast(m_callStack[i]), fileName, line, i - 1)); else - DEBUG_REPORT_PRINT(true, (" unknown(0x%08X) : caller %d\n", static_cast(m_callStack[i]), i - 1)); + DEBUG_REPORT_PRINT(true, (" unknown(0x%016llX) : caller %d\n", static_cast(m_callStack[i]), i - 1)); } } @@ -76,9 +76,9 @@ void CallStack::debugLog() const for (size_t i = 2; i < CALLSTACK_DEPTH && m_callStack[i]!=0; ++i) { if (DebugHelp::lookupAddress(m_callStack[i], libName, fileName, sizeof(fileName), line)) - DEBUG_REPORT_LOG(true, (" (0x%08X) %s(%d) : caller %d\n", static_cast(m_callStack[i]), fileName, line, i - 1)); + DEBUG_REPORT_LOG(true, (" (0x%016llX) %s(%d) : caller %d\n", static_cast(m_callStack[i]), fileName, line, i - 1)); else - DEBUG_REPORT_LOG(true, (" unknown(0x%08X) : caller %d\n", static_cast(m_callStack[i]), i - 1)); + DEBUG_REPORT_LOG(true, (" unknown(0x%016llX) : caller %d\n", static_cast(m_callStack[i]), i - 1)); } } diff --git a/engine/shared/library/sharedDebug/src/shared/CallStack.h b/engine/shared/library/sharedDebug/src/shared/CallStack.h index 376f0ed3..120791d0 100755 --- a/engine/shared/library/sharedDebug/src/shared/CallStack.h +++ b/engine/shared/library/sharedDebug/src/shared/CallStack.h @@ -40,7 +40,8 @@ private: private: - uint32 m_callStack[S_callStack]; + //-- Instruction addresses; must be pointer-width capable (see DebugHelp::getCallStack). + uint64 m_callStack[S_callStack]; }; // ====================================================================== diff --git a/engine/shared/library/sharedDebug/src/shared/CallStackCollector.cpp b/engine/shared/library/sharedDebug/src/shared/CallStackCollector.cpp index 9e91cbb4..8162421a 100755 --- a/engine/shared/library/sharedDebug/src/shared/CallStackCollector.cpp +++ b/engine/shared/library/sharedDebug/src/shared/CallStackCollector.cpp @@ -49,7 +49,7 @@ namespace CallStackCollectorNamespace ~Node(); CrcString const & getName() const; - void addCallStack(uint32 * callStack); + void addCallStack(uint64 * callStack); void debugReport() const; @@ -63,7 +63,7 @@ namespace CallStackCollectorNamespace public: - uint32 * m_callStack; + uint64 * m_callStack; int m_calls; }; @@ -125,10 +125,10 @@ CrcString const & CallStackCollectorNamespace::Node::getName() const // ---------------------------------------------------------------------- -void CallStackCollectorNamespace::Node::addCallStack(uint32 * const callStack) +void CallStackCollectorNamespace::Node::addCallStack(uint64 * const callStack) { //-- Compute crc of memory - uint32 const crc = Crc::calculate(callStack, (sizeof(uint32) * CALLSTACK_DEPTH)); + uint32 const crc = Crc::calculate(callStack, (sizeof(*callStack) * CALLSTACK_DEPTH)); //-- Find callstack in list CallStackEntryMap::iterator iter = m_callStackEntryMap.find(crc); @@ -140,8 +140,8 @@ void CallStackCollectorNamespace::Node::addCallStack(uint32 * const callStack) else { //-- Create new callstack - uint32 * const newCallStack = new uint32[CALLSTACK_DEPTH]; - memcpy(newCallStack, callStack, sizeof(*newCallStack)); + uint64 * const newCallStack = new uint64[CALLSTACK_DEPTH]; + memcpy(newCallStack, callStack, sizeof(*newCallStack) * CALLSTACK_DEPTH); CallStackEntry callStackEntry; callStackEntry.m_callStack = newCallStack; @@ -180,7 +180,7 @@ void CallStackCollectorNamespace::Node::debugReport() const if (DebugHelp::lookupAddress(callStackEntry->m_callStack[j], libName, fileName, sizeof(fileName), line)) REPORT_LOG(true, (" %s(%d) : caller %d\n", fileName, line, j - 1)); else - REPORT_LOG(true, (" unknown(0x%08X) : caller %d\n", static_cast(callStackEntry->m_callStack[j]), j - 1)); + REPORT_LOG(true, (" unknown(0x%016llX) : caller %d\n", static_cast(callStackEntry->m_callStack[j]), j - 1)); } } } @@ -218,7 +218,7 @@ void CallStackCollector::sample(char const * const name) } //-- Sample the callstack - uint32 callStack[CALLSTACK_DEPTH]; + uint64 callStack[CALLSTACK_DEPTH]; DebugHelp::getCallStack(&callStack[0], CALLSTACK_DEPTH); //-- Add to the node diff --git a/engine/shared/library/sharedDebug/src/win32/DebugHelp.cpp b/engine/shared/library/sharedDebug/src/win32/DebugHelp.cpp index b80a6a45..a138d781 100755 --- a/engine/shared/library/sharedDebug/src/win32/DebugHelp.cpp +++ b/engine/shared/library/sharedDebug/src/win32/DebugHelp.cpp @@ -481,7 +481,7 @@ bool DebugHelp::loadSymbolsForDll(const char *name) // ---------------------------------------------------------------------- #pragma warning (disable: 4740 4748) -void DebugHelp::getCallStack(uint32 *callStack, int sizeOfCallStack) +void DebugHelp::getCallStack(uint64 *callStack, int sizeOfCallStack) { { for (int i = 0; i < sizeOfCallStack; ++i) @@ -525,7 +525,7 @@ void DebugHelp::getCallStack(uint32 *callStack, int sizeOfCallStack) if (stackWalk64(IMAGE_FILE_MACHINE_I386, process, process, &stackFrame, &context, NULL, functionTableAccess, getModuleBase, NULL)) { const DWORD64 Offset = stackFrame.AddrPC.Offset; - *callStack = DWORD(Offset); + *callStack = static_cast(Offset); } } } @@ -537,7 +537,7 @@ void DebugHelp::reportCallStack(int const maxStackDepth) // look up the call stack information int const callStackOffset = 2; int const callStackSize = callStackOffset + maxStackDepth; - uint32 * callStack = static_cast(_alloca((callStackOffset + maxStackDepth) * sizeof(uint32))); + uint64 * callStack = static_cast(_alloca((callStackOffset + maxStackDepth) * sizeof(uint64))); getCallStack(callStack, callStackOffset + maxStackDepth); // look up the caller's file and line @@ -553,7 +553,7 @@ void DebugHelp::reportCallStack(int const maxStackDepth) if (lookupAddress(callStack[i], lib, file, sizeof(file), line)) REPORT_LOG(true, ("\t%s(%d) : caller %d\n", file, line, i-callStackOffset)); else - REPORT_LOG(true, ("\tunknown(0x%08X) : caller %d\n", static_cast(callStack[i]), i-callStackOffset)); + REPORT_LOG(true, ("\tunknown(0x%016llX) : caller %d\n", static_cast(callStack[i]), i-callStackOffset)); } } } @@ -561,7 +561,7 @@ void DebugHelp::reportCallStack(int const maxStackDepth) // ---------------------------------------------------------------------- -bool DebugHelp::lookupAddress(uint32 address, char *libName, char *fileName, int fileNameLength, int &line) +bool DebugHelp::lookupAddress(uint64 address, char *libName, char *fileName, int fileNameLength, int &line) { UNREF(libName); diff --git a/engine/shared/library/sharedDebug/src/win32/DebugHelp.h b/engine/shared/library/sharedDebug/src/win32/DebugHelp.h index 74e379ab..bb7483bb 100755 --- a/engine/shared/library/sharedDebug/src/win32/DebugHelp.h +++ b/engine/shared/library/sharedDebug/src/win32/DebugHelp.h @@ -23,9 +23,9 @@ public: static bool loadSymbolsForDll(const char *name); - static void getCallStack(uint32 *callStack, int sizeOfCallStack); + static void getCallStack(uint64 *callStack, int sizeOfCallStack); static void reportCallStack(int const maxStackDepth = 4); - static bool lookupAddress(uint32 address, char *libName, char *fileName, int fileNameLength, int &line); + static bool lookupAddress(uint64 address, char *libName, char *fileName, int fileNameLength, int &line); static bool writeMiniDump(char const *miniDumpFileName=0, PEXCEPTION_POINTERS exceptionPointers=0); }; diff --git a/engine/shared/library/sharedFoundation/src/shared/Fatal.cpp b/engine/shared/library/sharedFoundation/src/shared/Fatal.cpp index c684c6e4..a82a7160 100755 --- a/engine/shared/library/sharedFoundation/src/shared/Fatal.cpp +++ b/engine/shared/library/sharedFoundation/src/shared/Fatal.cpp @@ -62,7 +62,7 @@ static void formatMessage(char *buffer, int bufferLength, int stackDepth, const // look up the call stack information const int callStackSize = callStackOffset + stackDepth; - uint32 callStack[callStackOffset + maxStackDepth]; + uint64 callStack[callStackOffset + maxStackDepth]; // allow complete disable of the call stack lookup if (stackDepth < 0) @@ -82,7 +82,7 @@ static void formatMessage(char *buffer, int bufferLength, int stackDepth, const if (ConfigSharedFoundation::getLookUpCallStackNames() && DebugHelp::lookupAddress(callStack[callStackOffset], lib, file, sizeof(file), line)) snprintf(buffer, bufferLength, "%s(%d) : %s %08x: \n", file, line, type, static_cast(Crc::calculate(format))); else - snprintf(buffer, bufferLength, "(0x%08X) : %s %08x: \n", static_cast(callStack[callStackOffset]), type, static_cast(Crc::calculate(format))); + snprintf(buffer, bufferLength, "(0x%016llX) : %s %08x: \n", static_cast(callStack[callStackOffset]), type, static_cast(Crc::calculate(format))); } else { @@ -126,7 +126,7 @@ static void formatMessage(char *buffer, int bufferLength, int stackDepth, const if (ConfigSharedFoundation::getLookUpCallStackNames() && DebugHelp::lookupAddress(callStack[i], lib, file, sizeof(file), line)) snprintf(buffer, bufferLength, " %s(%d) : caller %d\n", file, line, i-callStackOffset); else - snprintf(buffer, bufferLength, " (0x%08X) : caller %d\n", static_cast(callStack[i]), i-callStackOffset); + snprintf(buffer, bufferLength, " (0x%016llX) : caller %d\n", static_cast(callStack[i]), i-callStackOffset); const int length = strlen(buffer); buffer += length; From 4fac50d2e57d7764b1559dec1d468422b0392c3f Mon Sep 17 00:00:00 2001 From: Sais Date: Sat, 25 Jul 2026 02:20:03 -0400 Subject: [PATCH 3/5] Back QueryPerformanceCounter with a monotonic clock The linux shim sampled gettimeofday(), which reports CLOCK_REALTIME and can be slewed or stepped backwards by time synchronisation. Clock::update() subtracts successive samples to derive frame time, so a backwards step produced a negative elapsed time, which AlterScheduler then reported as "no forward time movement" once per affected frame. Use clock_gettime(CLOCK_MONOTONIC) and keep microsecond units so the value still matches QueryPerformanceFrequency(). Falls back to gettimeofday() if the call fails. All getFrameStartTimeMs() consumers compare values relatively, so nothing depends on the previous epoch-based origin. --- .../src/linux/PlatformGlue.cpp | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/engine/shared/library/sharedFoundation/src/linux/PlatformGlue.cpp b/engine/shared/library/sharedFoundation/src/linux/PlatformGlue.cpp index 7937a2a7..9577df85 100755 --- a/engine/shared/library/sharedFoundation/src/linux/PlatformGlue.cpp +++ b/engine/shared/library/sharedFoundation/src/linux/PlatformGlue.cpp @@ -27,10 +27,23 @@ char* _itoa(int value, char* stringOut, int radix) bool QueryPerformanceCounter(__int64* time) { - struct timeval tv; - gettimeofday(&tv, nullptr); - *time = static_cast(tv.tv_sec); - *time = (*time * 1000000) + static_cast(tv.tv_usec); + // Must be monotonic. gettimeofday() reports CLOCK_REALTIME, which NTP can + // slew or step backwards; callers subtract successive samples to derive + // frame time, so a backwards step produced negative elapsed times (see + // AlterScheduler "no forward time movement"). CLOCK_MONOTONIC never goes + // backwards. Units stay microseconds to match QueryPerformanceFrequency(). + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) + { + struct timeval tv; + gettimeofday(&tv, nullptr); + *time = static_cast(tv.tv_sec); + *time = (*time * 1000000) + static_cast(tv.tv_usec); + return TRUE; + } + + *time = static_cast(ts.tv_sec); + *time = (*time * 1000000) + static_cast(ts.tv_nsec / 1000); return TRUE; } From 750f7d8601126ae720993e874336a9c54babe73a Mon Sep 17 00:00:00 2001 From: Sais Date: Sat, 25 Jul 2026 02:20:03 -0400 Subject: [PATCH 4/5] Stop dereferencing a 32-bit frame offset in the SIGSEGV handler JavaLibrary::fatalHandler() read the faulting address from a hardcoded 0x44 byte offset into its own frame. That constant describes the 32-bit x86 frame layout; on x86-64 it is misaligned and points at unrelated stack memory, and dereferencing it from inside a SIGSEGV handler risks a recursive fault that loses the crash report entirely. The original code carried a TODO noting the offset was never verified. Restrict that probe to __i386__ and rely on the portable __builtin_return_address() probe already present below it. Zero initialise the lib and file buffers, which the strstr() checks read whenever a lookup fails. --- .../serverScript/src/shared/JavaLibrary.cpp | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/engine/server/library/serverScript/src/shared/JavaLibrary.cpp b/engine/server/library/serverScript/src/shared/JavaLibrary.cpp index f5f415b7..ecfedd95 100755 --- a/engine/server/library/serverScript/src/shared/JavaLibrary.cpp +++ b/engine/server/library/serverScript/src/shared/JavaLibrary.cpp @@ -781,16 +781,26 @@ void JavaLibrary::fatalHandler(int signum) { // try to see if our call stack came from C or Java void *frameAddress = __builtin_frame_address(0); - // the address that generated the segfault is stored at an offset of 0x44 from - // the frame address - // @todo: find documentation on the offset to verify it is stable - void *crashAddress1 = *((void**)((static_cast(frameAddress)) + 0x44)); + // pass the crash address to addr2line to get the file name where the crash occurred + // These are zero initialized because the strstr() checks below read them + // whenever a lookup fails. static const int BUFLEN = 2048; - char lib1[BUFLEN], lib2[BUFLEN]; - char file1[BUFLEN], file2[BUFLEN]; - int line1, line2; - bool result1 = DebugHelp::lookupAddress(reinterpret_cast(crashAddress1), lib1, file1, BUFLEN, line1); + char lib1[BUFLEN] = { '\0' }, lib2[BUFLEN] = { '\0' }; + char file1[BUFLEN] = { '\0' }, file2[BUFLEN] = { '\0' }; + int line1 = 0, line2 = 0; + bool result1 = false; + + // The faulting address used to be read from a fixed 0x44 byte offset into + // this frame. That constant describes the 32-bit x86 frame layout only; on + // x86-64 it is both misaligned and meaningless, and dereferencing it from + // inside a SIGSEGV handler risks a recursive fault that loses the crash + // report entirely. The __builtin_return_address() probe below is portable + // and already covers this case. +#if defined(__i386__) + void *crashAddress1 = *((void**)((static_cast(frameAddress)) + 0x44)); + result1 = DebugHelp::lookupAddress(reinterpret_cast(crashAddress1), lib1, file1, BUFLEN, line1); +#endif // do a second test based on the return address // it turns out that in some java crashes we don't even have 2 return From a7c14599c8a3093b8e1f7be1b6a05117aa1c7c12 Mon Sep 17 00:00:00 2001 From: Sais Date: Fri, 24 Jul 2026 21:10:27 -0400 Subject: [PATCH 5/5] Support Oracle 19 x64 Instant Client discovery --- cmake/linux/FindOracle.cmake | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmake/linux/FindOracle.cmake b/cmake/linux/FindOracle.cmake index d6074ead..73cc9329 100644 --- a/cmake/linux/FindOracle.cmake +++ b/cmake/linux/FindOracle.cmake @@ -37,10 +37,11 @@ if(DEFINED ENV{ORACLE_HOME}) ${ORACLE_HOME}/OCI/include) # Oracle XE on Windows set(ORACLE_OCI_NAMES clntsh libclntsh oci) - set(ORACLE_NNZ_NAMES libnnz18 nnz18 libnnz21 nnz21 ociw32) + set(ORACLE_NNZ_NAMES libnnz18 nnz18 libnnz19 nnz19 libnnz21 nnz21 ociw32) set(ORACLE_OCCI_NAMES libocci occi oraocci10 oraocci11) set(ORACLE_LIB_DIR + ${ORACLE_HOME} ${ORACLE_HOME}/lib ${ORACLE_HOME}/sdk/lib # Oracle SDK ${ORACLE_HOME}/sdk/lib/msvc @@ -76,4 +77,4 @@ endif(DEFINED ENV{ORACLE_HOME}) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Oracle DEFAULT_MSG ORACLE_LIBRARY ORACLE_INCLUDE_DIR) -mark_as_advanced(ORACLE_INCLUDE_DIR ORACLE_LIBRARY) \ No newline at end of file +mark_as_advanced(ORACLE_INCLUDE_DIR ORACLE_LIBRARY)