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.
This commit is contained in:
Sais
2026-07-25 03:52:43 -04:00
parent 55c8f225f2
commit ec3419dbb0
8 changed files with 49 additions and 26 deletions
@@ -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<void **>(callStack), sizeOfCallStack));
if (sizeOfCallStack > static_cast<int>(cs_maximumFrameCount))
sizeOfCallStack = static_cast<int>(cs_maximumFrameCount);
void *frames[cs_maximumFrameCount];
int const frameCount = backtrace(frames, sizeOfCallStack);
for (int i = 0; i < frameCount; ++i)
callStack[i] = reinterpret_cast<uint64>(frames[i]);
}
// ======================================================================
@@ -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);
};
@@ -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<int>(m_callStack[i]), fileName, line, i - 1));
DEBUG_REPORT_PRINT(true, (" (0x%016llX) %s(%d) : caller %d\n", static_cast<unsigned long long>(m_callStack[i]), fileName, line, i - 1));
else
DEBUG_REPORT_PRINT(true, (" unknown(0x%08X) : caller %d\n", static_cast<int>(m_callStack[i]), i - 1));
DEBUG_REPORT_PRINT(true, (" unknown(0x%016llX) : caller %d\n", static_cast<unsigned long long>(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<int>(m_callStack[i]), fileName, line, i - 1));
DEBUG_REPORT_LOG(true, (" (0x%016llX) %s(%d) : caller %d\n", static_cast<unsigned long long>(m_callStack[i]), fileName, line, i - 1));
else
DEBUG_REPORT_LOG(true, (" unknown(0x%08X) : caller %d\n", static_cast<int>(m_callStack[i]), i - 1));
DEBUG_REPORT_LOG(true, (" unknown(0x%016llX) : caller %d\n", static_cast<unsigned long long>(m_callStack[i]), i - 1));
}
}
@@ -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];
};
// ======================================================================
@@ -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<int>(callStackEntry->m_callStack[j]), j - 1));
REPORT_LOG(true, (" unknown(0x%016llX) : caller %d\n", static_cast<unsigned long long>(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
@@ -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<uint64>(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<uint32 *>(_alloca((callStackOffset + maxStackDepth) * sizeof(uint32)));
uint64 * callStack = static_cast<uint64 *>(_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<int>(callStack[i]), i-callStackOffset));
REPORT_LOG(true, ("\tunknown(0x%016llX) : caller %d\n", static_cast<unsigned long long>(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);
@@ -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);
};
@@ -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<int>(Crc::calculate(format)));
else
snprintf(buffer, bufferLength, "(0x%08X) : %s %08x: \n", static_cast<int>(callStack[callStackOffset]), type, static_cast<int>(Crc::calculate(format)));
snprintf(buffer, bufferLength, "(0x%016llX) : %s %08x: \n", static_cast<unsigned long long>(callStack[callStackOffset]), type, static_cast<int>(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<int>(callStack[i]), i-callStackOffset);
snprintf(buffer, bufferLength, " (0x%016llX) : caller %d\n", static_cast<unsigned long long>(callStack[i]), i-callStackOffset);
const int length = strlen(buffer);
buffer += length;