report a caught exception at its own line, not at line 0

_ExceptionMessage builds the full call stack of the exception it was given
and then calls _FailMessage with "",0,"", so every caught sgp:: or
vfs::Exception produces an identical, locationless report - the bucket
telemetry will see most of and can act on least. Fail with the innermost
frame instead, which is the frame that knows where it came from.

That feeds a runtime-built string to a _FailMessage that passed it to
sprintf as the format string, so copy it bounded instead. AssertMsg call
sites already build messages out of game state, and a %s in one of those
would read arguments that were never passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Marco Antonio J. Costa
2026-07-31 16:51:06 -03:00
committed by majcosta
co-authored by Claude Opus 5
parent 56e6873b80
commit 40bf6326c8
+23 -4
View File
@@ -412,10 +412,12 @@ void _FailMessage(const char* message, unsigned lineNum, const char * functionNa
outputString << "{ " << GetTickCount() << " } " << basicInformation.str();
//Build the output strings
// Never as a format string: AssertMsg call sites build this out of game state,
// so a stray %s in it would read arguments that were never passed.
if( message )
sprintf( gubAssertString, message );
snprintf( gubAssertString, sizeof( gubAssertString ), "%s", message );
else
sprintf( gubAssertString, "" );
gubAssertString[0] = '\0';
//Output to debugger
if (gfRecordToDebugger)
@@ -491,6 +493,23 @@ STR8 String(const STR8 String, ...)
}
// Fail with the innermost frame of the exception list, not with nothing. The crash
// report can only stamp what _FailMessage was handed, and a caught exception knows
// exactly where it came from — passing "",0,"" turns every one of them into the same
// locationless report. The utf8() temporaries live to the end of the call, and the
// crash handler reads them synchronously inside it.
static void FailFromExceptionList()
{
if (g_ExceptionList.empty())
{
_FailMessage("", 0, "");
return;
}
SExceptionData const& innermost = g_ExceptionList.front();
_FailMessage(innermost.message.utf8().c_str(), innermost.line,
innermost.function.utf8().c_str(), innermost.file.utf8().c_str());
}
void _ExceptionMessage( sgp::Exception &ex )
{
g_ExceptionList.clear();
@@ -504,7 +523,7 @@ void _ExceptionMessage( sgp::Exception &ex )
exd.line = (*it).line;
g_ExceptionList.push_back(exd);
}
_FailMessage("",0,"");
FailFromExceptionList();
}
void _ExceptionMessage( vfs::Exception &ex )
@@ -520,7 +539,7 @@ void _ExceptionMessage( vfs::Exception &ex )
exd.line = (*it).line;
g_ExceptionList.push_back(exd);
}
_FailMessage("",0,"");
FailFromExceptionList();
}
#include <vfs/Core/vfs_string.h>