From ee01103b67f6c93a7137fc813adf29ab87a1f27e Mon Sep 17 00:00:00 2001 From: "Marco Antonio J. Costa" Date: Wed, 22 Jul 2026 12:08:40 -0300 Subject: [PATCH] pass a string, not a std::wstring object, to a %s The AI deadlock message hands ScreenMsg an object where its format string promises a pointer: ScreenMsg(..., L"Aborting AI deadlock for [%d] %s %s data %d", pSoldier->ubID.i, pSoldier->GetName(), utf8_to_wstring(std::string(szAction[...])), ...); utf8_to_wstring returns std::wstring by value. ScreenMsg is variadic, so the whole object is pushed and %s then reads the first bytes of it as a pointer. What that prints, or whether it survives printing it, is not defined. clang says as much: the call will abort at runtime. Adding .c_str() passes what the format asked for. The temporary lives until the end of the statement, so the pointer is good for the duration of the call. The only other use of utf8_to_wstring in this file has the same shape and is commented out; it is left as it is. Verification: ninja -C build parse # AIMain.cpp clean ninja -C build -k 0 # Release, four applications, green ninja -C build-debug -k 0 # Debug, four applications, green Co-Authored-By: Claude Opus 4.8 --- TacticalAI/AIMain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TacticalAI/AIMain.cpp b/TacticalAI/AIMain.cpp index 800f47c35..66e3cf511 100644 --- a/TacticalAI/AIMain.cpp +++ b/TacticalAI/AIMain.cpp @@ -697,7 +697,7 @@ void HandleSoldierAI( SOLDIERTYPE *pSoldier ) // FIXME - this function is named // ATE: Display message that deadlock occured... LiveMessage( "Breaking Deadlock" ); - ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"Aborting AI deadlock for [%d] %s %s data %d", pSoldier->ubID.i, pSoldier->GetName(), utf8_to_wstring(std::string(szAction[pSoldier->aiData.bAction])), pSoldier->aiData.usActionData); + ScreenMsg(FONT_MCOLOR_LTRED, MSG_INTERFACE, L"Aborting AI deadlock for [%d] %s %s data %d", pSoldier->ubID.i, pSoldier->GetName(), utf8_to_wstring(std::string(szAction[pSoldier->aiData.bAction])).c_str(), pSoldier->aiData.usActionData); DebugAI(String("Aborting AI deadlock for [%d] %s data %d", pSoldier->ubID, szAction[pSoldier->aiData.bAction], pSoldier->aiData.usActionData)); #ifdef JA2TESTVERSION