From 9a57def5a6e82274f577950ed2359fbcdb2a52af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Tue, 13 Jun 2023 21:06:48 +0200 Subject: [PATCH 1/4] Add templated `str_append` function for arrays with fixed size --- src/base/system.cpp | 2 +- src/base/system.h | 17 +++++++++++++++ src/engine/client/client.cpp | 8 +++---- src/engine/client/friends.cpp | 6 +++--- src/engine/client/graphics_threaded.cpp | 6 +++--- src/engine/client/text.cpp | 2 +- src/engine/client/updater.cpp | 4 ++-- src/engine/server/server.cpp | 10 ++++----- src/engine/shared/console.cpp | 6 +++--- src/engine/shared/fifo.cpp | 2 +- src/engine/shared/storage.cpp | 4 ++-- src/game/client/components/binds.cpp | 4 ++-- src/game/client/components/chat.cpp | 18 ++++++++-------- src/game/client/components/console.cpp | 4 ++-- src/game/client/components/menus.cpp | 2 +- src/game/client/components/menus_demo.cpp | 6 +++--- src/game/client/components/scoreboard.cpp | 10 ++++----- src/game/client/components/statboard.cpp | 2 +- src/game/client/components/voting.cpp | 10 ++++----- src/game/server/gamecontext.cpp | 6 +++--- src/game/server/save.cpp | 4 ++-- src/game/server/scoreworker.cpp | 26 +++++++++++------------ src/game/server/teams.cpp | 8 +++---- src/tools/config_common.h | 2 +- 24 files changed, 93 insertions(+), 76 deletions(-) diff --git a/src/base/system.cpp b/src/base/system.cpp index 0be8541c9..5348002ba 100644 --- a/src/base/system.cpp +++ b/src/base/system.cpp @@ -3991,7 +3991,7 @@ int open_file(const char *path) { if(!fs_getcwd(workingDir, sizeof(workingDir))) return 0; - str_append(workingDir, "/", sizeof(workingDir)); + str_append(workingDir, "/"); } else workingDir[0] = '\0'; diff --git a/src/base/system.h b/src/base/system.h index ac22a8139..7ec1b2ee9 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -1194,6 +1194,23 @@ std::string windows_format_system_message(unsigned long error); */ void str_append(char *dst, const char *src, int dst_size); +/** + * Appends a string to a fixed-size array of chars. + * + * @ingroup Strings + * + * @param dst Array that shall receive the string. + * @param src String to append. + * + * @remark The strings are treated as zero-terminated strings. + * @remark Guarantees that dst string will contain zero-termination. + */ +template +void str_append(char (&dst)[N], const char *src) +{ + str_append(dst, src, N); +} + /** * Copies a string to another. * diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 5b03d3f92..f6dc76413 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -2165,7 +2165,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy) if(g_Config.m_ClRunOnJoin[0]) { str_format(aBuf, sizeof(aBuf), ";%s", g_Config.m_ClRunOnJoin); - str_append(aBufMsg, aBuf, sizeof(aBufMsg)); + str_append(aBufMsg, aBuf); } if(g_Config.m_ClDummyDefaultEyes || g_Config.m_ClPlayerDefaultEyes) { @@ -2195,7 +2195,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy) if(aBufEmote[0]) { str_format(aBuf, sizeof(aBuf), ";%s", aBufEmote); - str_append(aBufMsg, aBuf, sizeof(aBufMsg)); + str_append(aBufMsg, aBuf); } } MsgP.m_pMessage = aBufMsg; @@ -4892,8 +4892,8 @@ void CClient::RequestDDNetInfo() { char aEscaped[128]; EscapeUrl(aEscaped, sizeof(aEscaped), PlayerName()); - str_append(aUrl, "?name=", sizeof(aUrl)); - str_append(aUrl, aEscaped, sizeof(aUrl)); + str_append(aUrl, "?name="); + str_append(aUrl, aEscaped); } // Use ipv4 so we can know the ingame ip addresses of players before they join game servers diff --git a/src/engine/client/friends.cpp b/src/engine/client/friends.cpp index ed7825f78..925ecc242 100644 --- a/src/engine/client/friends.cpp +++ b/src/engine/client/friends.cpp @@ -168,13 +168,13 @@ void CFriends::ConfigSaveCallback(IConfigManager *pConfigManager, void *pUserDat { str_copy(aBuf, pSelf->m_Foes ? "add_foe " : "add_friend "); - str_append(aBuf, "\"", sizeof(aBuf)); + str_append(aBuf, "\""); char *pDst = aBuf + str_length(aBuf); str_escape(&pDst, pSelf->m_aFriends[i].m_aName, pEnd); - str_append(aBuf, "\" \"", sizeof(aBuf)); + str_append(aBuf, "\" \""); pDst = aBuf + str_length(aBuf); str_escape(&pDst, pSelf->m_aFriends[i].m_aClan, pEnd); - str_append(aBuf, "\"", sizeof(aBuf)); + str_append(aBuf, "\""); pConfigManager->WriteLine(aBuf); } diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 8b0a9ae55..f094ab9cb 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -672,13 +672,13 @@ int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int Sto { if(!First) { - str_append(Warning.m_aWarningMsg, ", ", sizeof(Warning.m_aWarningMsg)); + str_append(Warning.m_aWarningMsg, ", "); } - str_append(Warning.m_aWarningMsg, EXPLANATION[i], sizeof(Warning.m_aWarningMsg)); + str_append(Warning.m_aWarningMsg, EXPLANATION[i]); First = false; } } - str_append(Warning.m_aWarningMsg, " unsupported", sizeof(Warning.m_aWarningMsg)); + str_append(Warning.m_aWarningMsg, " unsupported"); m_vWarnings.emplace_back(Warning); } } diff --git a/src/engine/client/text.cpp b/src/engine/client/text.cpp index a4d4ee5eb..35ead4ebe 100644 --- a/src/engine/client/text.cpp +++ b/src/engine/client/text.cpp @@ -1031,7 +1031,7 @@ public: void AppendTextContainer(STextContainerIndex TextContainerIndex, CTextCursor *pCursor, const char *pText, int Length = -1) override { STextContainer &TextContainer = GetTextContainer(TextContainerIndex); - str_append(TextContainer.m_aDebugText, pText, sizeof(TextContainer.m_aDebugText)); + str_append(TextContainer.m_aDebugText, pText); // calculate the font size of the displayed glyphs float ScreenX0, ScreenY0, ScreenX1, ScreenY1; diff --git a/src/engine/client/updater.cpp b/src/engine/client/updater.cpp index c149acb42..716fe057c 100644 --- a/src/engine/client/updater.cpp +++ b/src/engine/client/updater.cpp @@ -315,7 +315,7 @@ void CUpdater::PerformUpdate() char aBuf[512]; str_copy(aBuf, pFile, sizeof(aBuf)); // SDL str_copy(aBuf + len - 4, "-" PLAT_NAME, sizeof(aBuf) - len + 4); // -win32 - str_append(aBuf, pFile + len - 4, sizeof(aBuf)); // .dll + str_append(aBuf, pFile + len - 4); // .dll FetchFile(aBuf, pFile); #endif // Ignore DLL downloads on other platforms @@ -326,7 +326,7 @@ void CUpdater::PerformUpdate() char aBuf[512]; str_copy(aBuf, pFile, sizeof(aBuf)); // libsteam_api str_copy(aBuf + len - 3, "-" PLAT_NAME, sizeof(aBuf) - len + 3); // -linux-x86_64 - str_append(aBuf, pFile + len - 3, sizeof(aBuf)); // .so + str_append(aBuf, pFile + len - 3); // .so FetchFile(aBuf, pFile); #endif // Ignore DLL downloads on other platforms, on Linux we statically link anyway diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 5daa7aabe..7737233c8 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -1293,11 +1293,11 @@ void CServer::SendRconLogLine(int ClientID, const CLogMessage *pMessage) { str_append(aLine, pLine, pStart - pLine + 1); str_append(aLine, pStart + 2, pStart - pLine + pEnd - pStart - 1); - str_append(aLine, pEnd + 2, sizeof(aLine)); + str_append(aLine, pEnd + 2); str_append(aLineWithoutIps, pLine, pStart - pLine + 1); - str_append(aLineWithoutIps, "XXX", sizeof(aLineWithoutIps)); - str_append(aLineWithoutIps, pEnd + 2, sizeof(aLineWithoutIps)); + str_append(aLineWithoutIps, "XXX"); + str_append(aLineWithoutIps, pEnd + 2); pLine = aLine; pLineWithoutIps = aLineWithoutIps; @@ -2319,12 +2319,12 @@ void CServer::UpdateRegisterServerInfo() m_aClients[i].m_Score.value_or(-9999), JsonBool(GameServer()->IsClientPlayer(i)), aExtraPlayerInfo); - str_append(aInfo, aClientInfo, sizeof(aInfo)); + str_append(aInfo, aClientInfo); FirstPlayer = false; } } - str_append(aInfo, "]}", sizeof(aInfo)); + str_append(aInfo, "]}"); m_pRegister->OnNewInfo(aInfo); } diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index 4870027ed..bcc303031 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -732,9 +732,9 @@ void CConsole::ConCommandStatus(IResult *pResult, void *pUser) if(Used > 0) { Used += 2; - str_append(aBuf, ", ", sizeof(aBuf)); + str_append(aBuf, ", "); } - str_append(aBuf, pCommand->m_pName, sizeof(aBuf)); + str_append(aBuf, pCommand->m_pName); Used += Length; } else @@ -927,7 +927,7 @@ void CConsole::ConToggle(IConsole::IResult *pResult, void *pUser) str_format(aBuf, sizeof(aBuf), "%s \"", pResult->GetString(0)); char *pDst = aBuf + str_length(aBuf); str_escape(&pDst, pStr, aBuf + sizeof(aBuf)); - str_append(aBuf, "\"", sizeof(aBuf)); + str_append(aBuf, "\""); pConsole->ExecuteLine(aBuf); aBuf[0] = 0; } diff --git a/src/engine/shared/fifo.cpp b/src/engine/shared/fifo.cpp index d0c130a35..7ed0b296b 100644 --- a/src/engine/shared/fifo.cpp +++ b/src/engine/shared/fifo.cpp @@ -92,7 +92,7 @@ void CFifo::Init(IConsole *pConsole, char *pFifoFile, int Flag) } str_copy(m_aFilename, "\\\\.\\pipe\\"); - str_append(m_aFilename, pFifoFile, sizeof(m_aFilename)); + str_append(m_aFilename, pFifoFile); m_Flag = Flag; const std::wstring WideFilename = windows_utf8_to_wide(m_aFilename); diff --git a/src/engine/shared/storage.cpp b/src/engine/shared/storage.cpp index f344e36f3..929191733 100644 --- a/src/engine/shared/storage.cpp +++ b/src/engine/shared/storage.cpp @@ -112,7 +112,7 @@ public: { char aBuffer[IO_MAX_PATH_LENGTH]; str_copy(aBuffer, pArgv0, Pos + 1); - str_append(aBuffer, "/storage.cfg", sizeof(aBuffer)); + str_append(aBuffer, "/storage.cfg"); File = io_open(aBuffer, IOFLAG_READ | IOFLAG_SKIP_BOM); } @@ -294,7 +294,7 @@ public: return; } #if defined(CONF_PLATFORM_MACOS) - str_append(m_aBinarydir, "/../../../DDNet-Server.app/Contents/MacOS", sizeof(m_aBinarydir)); + str_append(m_aBinarydir, "/../../../DDNet-Server.app/Contents/MacOS"); str_format(aBuf, sizeof(aBuf), "%s/" PLAT_SERVER_EXEC, m_aBinarydir); if(fs_is_file(aBuf)) { diff --git a/src/game/client/components/binds.cpp b/src/game/client/components/binds.cpp index 3080fa710..79dbb920b 100644 --- a/src/game/client/components/binds.cpp +++ b/src/game/client/components/binds.cpp @@ -419,8 +419,8 @@ const char *CBinds::GetKeyBindModifiersName(int ModifierCombination) { if(ModifierCombination & (1 << k)) { - str_append(aModifier, GetModifierName(k), sizeof(aModifier)); - str_append(aModifier, "+", sizeof(aModifier)); + str_append(aModifier, GetModifierName(k)); + str_append(aModifier, "+"); } } return aModifier; diff --git a/src/game/client/components/chat.cpp b/src/game/client/components/chat.cpp index bd33b0646..532ac7b49 100644 --- a/src/game/client/components/chat.cpp +++ b/src/game/client/components/chat.cpp @@ -299,17 +299,17 @@ bool CChat::OnInput(const IInput::CEvent &Event) str_truncate(aBuf, sizeof(aBuf), m_Input.GetString(), m_PlaceholderOffset); // add the command - str_append(aBuf, "/", sizeof(aBuf)); - str_append(aBuf, pCompletionCommand->m_pName, sizeof(aBuf)); + str_append(aBuf, "/"); + str_append(aBuf, pCompletionCommand->m_pName); // add separator const char *pSeparator = pCompletionCommand->m_pParams[0] == '\0' ? "" : " "; - str_append(aBuf, pSeparator, sizeof(aBuf)); + str_append(aBuf, pSeparator); if(*pSeparator) - str_append(aBuf, pSeparator, sizeof(aBuf)); + str_append(aBuf, pSeparator); // add part after the name - str_append(aBuf, m_Input.GetString() + m_PlaceholderOffset + m_PlaceholderLength, sizeof(aBuf)); + str_append(aBuf, m_Input.GetString() + m_PlaceholderOffset + m_PlaceholderLength); m_PlaceholderLength = str_length(pSeparator) + str_length(pCompletionCommand->m_pName) + 1; m_Input.Set(aBuf); @@ -360,7 +360,7 @@ bool CChat::OnInput(const IInput::CEvent &Event) str_truncate(aBuf, sizeof(aBuf), m_Input.GetString(), m_PlaceholderOffset); // add the name - str_append(aBuf, pCompletionString, sizeof(aBuf)); + str_append(aBuf, pCompletionString); // add separator const char *pSeparator = ""; @@ -369,10 +369,10 @@ bool CChat::OnInput(const IInput::CEvent &Event) else if(m_PlaceholderOffset == 0) pSeparator = ":"; if(*pSeparator) - str_append(aBuf, pSeparator, sizeof(aBuf)); + str_append(aBuf, pSeparator); // add part after the name - str_append(aBuf, m_Input.GetString() + m_PlaceholderOffset + m_PlaceholderLength, sizeof(aBuf)); + str_append(aBuf, m_Input.GetString() + m_PlaceholderOffset + m_PlaceholderLength); m_PlaceholderLength = str_length(pSeparator) + str_length(pCompletionString); m_Input.Set(aBuf); @@ -883,7 +883,7 @@ void CChat::OnPrepareLines() str_format(aName, sizeof(aName), "%d: ", m_aLines[r].m_ClientID); } - str_append(aName, m_aLines[r].m_aName, sizeof(aName)); + str_append(aName, m_aLines[r].m_aName); char aCount[12]; if(m_aLines[r].m_ClientID < 0) diff --git a/src/game/client/components/console.cpp b/src/game/client/components/console.cpp index 7c452a259..127177085 100644 --- a/src/game/client/components/console.cpp +++ b/src/game/client/components/console.cpp @@ -188,10 +188,10 @@ void CGameConsole::CInstance::PossibleArgumentsCompleteCallback(int Index, const // get command char aBuf[512]; StrCopyUntilSpace(aBuf, sizeof(aBuf), pInstance->GetString()); - str_append(aBuf, " ", sizeof(aBuf)); + str_append(aBuf, " "); // append argument - str_append(aBuf, pStr, sizeof(aBuf)); + str_append(aBuf, pStr); pInstance->m_Input.Set(aBuf); } } diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index eee118bd4..24d50a397 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -1522,7 +1522,7 @@ int CMenus::Render() char aBufNew[IO_MAX_PATH_LENGTH]; str_format(aBufNew, sizeof(aBufNew), "%s/%s", m_aCurrentDemoFolder, m_DemoRenameInput.GetString()); if(!str_endswith(aBufNew, ".demo")) - str_append(aBufNew, ".demo", sizeof(aBufNew)); + str_append(aBufNew, ".demo"); if(Storage()->FileExists(aBufNew, m_vDemos[m_DemolistSelectedIndex].m_StorageType)) { diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index 270e7ef6b..414548bde 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -676,7 +676,7 @@ void CMenus::RenderDemoPlayerSliceSavePopup(CUIRect MainView) { char aDemoName[IO_MAX_PATH_LENGTH]; DemoPlayer()->GetDemoName(aDemoName, sizeof(aDemoName)); - str_append(aDemoName, ".demo", sizeof(aDemoName)); + str_append(aDemoName, ".demo"); if(!str_endswith(m_DemoSliceInput.GetString(), ".demo")) m_DemoSliceInput.Append(".demo"); @@ -1160,8 +1160,8 @@ void CMenus::RenderDemoList(CUIRect MainView) fs_parent_dir(m_aCurrentDemoFolder); else // sub folder { - str_append(m_aCurrentDemoFolder, "/", sizeof(m_aCurrentDemoFolder)); - str_append(m_aCurrentDemoFolder, m_vDemos[m_DemolistSelectedIndex].m_aFilename, sizeof(m_aCurrentDemoFolder)); + str_append(m_aCurrentDemoFolder, "/"); + str_append(m_aCurrentDemoFolder, m_vDemos[m_DemolistSelectedIndex].m_aFilename); m_DemolistStorageType = m_vDemos[m_DemolistSelectedIndex].m_StorageType; } DemolistPopulate(); diff --git a/src/game/client/components/scoreboard.cpp b/src/game/client/components/scoreboard.cpp index b4354a82e..2ce876279 100644 --- a/src/game/client/components/scoreboard.cpp +++ b/src/game/client/components/scoreboard.cpp @@ -191,7 +191,7 @@ void CScoreboard::RenderScoreboard(float x, float y, float w, int Team, const ch while(TextRender()->TextWidth(TitleFontsize, aBuf, -1, -1.0f) > TitleWidth) aBuf[str_length(aBuf) - 1] = '\0'; if(str_comp(aBuf, Client()->GetCurrentMap())) - str_append(aBuf, "…", sizeof(aBuf)); + str_append(aBuf, "…"); pTitle = aBuf; } } @@ -531,25 +531,25 @@ void CScoreboard::RenderRecordingNotification(float x) { str_time((int64_t)m_pClient->DemoRecorder(RECORDER_MANUAL)->Length() * 100, TIME_HOURS, aTime, sizeof(aTime)); str_format(aBuf2, sizeof(aBuf2), "%s %s ", Localize("Manual"), aTime); - str_append(aBuf, aBuf2, sizeof(aBuf)); + str_append(aBuf, aBuf2); } if(m_pClient->DemoRecorder(RECORDER_RACE)->IsRecording()) { str_time((int64_t)m_pClient->DemoRecorder(RECORDER_RACE)->Length() * 100, TIME_HOURS, aTime, sizeof(aTime)); str_format(aBuf2, sizeof(aBuf2), "%s %s ", Localize("Race"), aTime); - str_append(aBuf, aBuf2, sizeof(aBuf)); + str_append(aBuf, aBuf2); } if(m_pClient->DemoRecorder(RECORDER_AUTO)->IsRecording()) { str_time((int64_t)m_pClient->DemoRecorder(RECORDER_AUTO)->Length() * 100, TIME_HOURS, aTime, sizeof(aTime)); str_format(aBuf2, sizeof(aBuf2), "%s %s ", Localize("Auto"), aTime); - str_append(aBuf, aBuf2, sizeof(aBuf)); + str_append(aBuf, aBuf2); } if(m_pClient->DemoRecorder(RECORDER_REPLAYS)->IsRecording()) { str_time((int64_t)m_pClient->DemoRecorder(RECORDER_REPLAYS)->Length() * 100, TIME_HOURS, aTime, sizeof(aTime)); str_format(aBuf2, sizeof(aBuf2), "%s %s ", Localize("Replay"), aTime); - str_append(aBuf, aBuf2, sizeof(aBuf)); + str_append(aBuf, aBuf2); } if(!aBuf[0]) diff --git a/src/game/client/components/statboard.cpp b/src/game/client/components/statboard.cpp index 07196b5f0..b3ef5083f 100644 --- a/src/game/client/components/statboard.cpp +++ b/src/game/client/components/statboard.cpp @@ -518,7 +518,7 @@ void CStatboard::FormatStats(char *pDest, size_t DestSize) pStats->m_FlagGrabs, // Flag grabs pStats->m_FlagCaptures); // Flag captures - str_append(aPlayerStats, aBuf, sizeof(aPlayerStats)); + str_append(aPlayerStats, aBuf); } str_format(pDest, DestSize, "%s\n\n%s", aServerStats, aPlayerStats); diff --git a/src/game/client/components/voting.cpp b/src/game/client/components/voting.cpp index f5fcdec5e..1eebaf264 100644 --- a/src/game/client/components/voting.cpp +++ b/src/game/client/components/voting.cpp @@ -78,10 +78,10 @@ void CVoting::CallvoteOption(int OptionID, const char *pReason, bool ForceVote) str_copy(aBuf, "force_vote option \""); char *pDst = aBuf + str_length(aBuf); str_escape(&pDst, pOption->m_aDescription, aBuf + sizeof(aBuf)); - str_append(aBuf, "\" \"", sizeof(aBuf)); + str_append(aBuf, "\" \""); pDst = aBuf + str_length(aBuf); str_escape(&pDst, pReason, aBuf + sizeof(aBuf)); - str_append(aBuf, "\"", sizeof(aBuf)); + str_append(aBuf, "\""); Client()->Rcon(aBuf); } else @@ -105,7 +105,7 @@ void CVoting::RemovevoteOption(int OptionID) str_copy(aBuf, "remove_vote \""); char *pDst = aBuf + str_length(aBuf); str_escape(&pDst, pOption->m_aDescription, aBuf + sizeof(aBuf)); - str_append(aBuf, "\"", sizeof(aBuf)); + str_append(aBuf, "\""); Client()->Rcon(aBuf); break; } @@ -121,10 +121,10 @@ void CVoting::AddvoteOption(const char *pDescription, const char *pCommand) str_copy(aBuf, "add_vote \""); char *pDst = aBuf + str_length(aBuf); str_escape(&pDst, pDescription, aBuf + sizeof(aBuf)); - str_append(aBuf, "\" \"", sizeof(aBuf)); + str_append(aBuf, "\" \""); pDst = aBuf + str_length(aBuf); str_escape(&pDst, pCommand, aBuf + sizeof(aBuf)); - str_append(aBuf, "\"", sizeof(aBuf)); + str_append(aBuf, "\""); Client()->Rcon(aBuf); } diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 8f7864c14..e2b92ccbc 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -4440,16 +4440,16 @@ void CGameContext::OnUpdatePlayerServerInfo(char *aBuf, int BufSize, int ID) apPartNames[i], EscapeJson(aCSkinName, sizeof(aCSkinName), TeeInfo.m_apSkinPartNames[i])); - str_append(aJsonSkin, aPartBuf, sizeof(aJsonSkin)); + str_append(aJsonSkin, aPartBuf); if(TeeInfo.m_aUseCustomColors[i]) { str_format(aPartBuf, sizeof(aPartBuf), ",\"color\":%d", TeeInfo.m_aSkinPartColors[i]); - str_append(aJsonSkin, aPartBuf, sizeof(aJsonSkin)); + str_append(aJsonSkin, aPartBuf); } - str_append(aJsonSkin, "}", sizeof(aJsonSkin)); + str_append(aJsonSkin, "}"); } } diff --git a/src/game/server/save.cpp b/src/game/server/save.cpp index 01a907054..abdce8acf 100644 --- a/src/game/server/save.cpp +++ b/src/game/server/save.cpp @@ -581,7 +581,7 @@ char *CSaveTeam::GetString() { char aBuf[1024]; str_format(aBuf, sizeof(aBuf), "\n%s", m_pSavedTees[i].GetString(this)); - str_append(m_aString, aBuf, sizeof(m_aString)); + str_append(m_aString, aBuf); } if(m_pSwitchers && m_HighestSwitchNumber) @@ -590,7 +590,7 @@ char *CSaveTeam::GetString() { char aBuf[64]; str_format(aBuf, sizeof(aBuf), "\n%d\t%d\t%d", m_pSwitchers[i].m_Status, m_pSwitchers[i].m_EndTime, m_pSwitchers[i].m_Type); - str_append(m_aString, aBuf, sizeof(m_aString)); + str_append(m_aString, aBuf); } } diff --git a/src/game/server/scoreworker.cpp b/src/game/server/scoreworker.cpp index 0cc33fa01..49f3a91c0 100644 --- a/src/game/server/scoreworker.cpp +++ b/src/game/server/scoreworker.cpp @@ -215,7 +215,7 @@ bool CScoreWorker::MapVote(IDbConnection *pSqlServer, const ISqlData *pGameData, char aMapPrefix[128]; str_copy(aMapPrefix, pData->m_aName, sizeof(aMapPrefix)); - str_append(aMapPrefix, "%", sizeof(aMapPrefix)); + str_append(aMapPrefix, "%"); char aBuf[768]; str_format(aBuf, sizeof(aBuf), @@ -275,7 +275,7 @@ bool CScoreWorker::MapInfo(IDbConnection *pSqlServer, const ISqlData *pGameData, char aMapPrefix[128]; str_copy(aMapPrefix, pData->m_aName, sizeof(aMapPrefix)); - str_append(aMapPrefix, "%", sizeof(aMapPrefix)); + str_append(aMapPrefix, "%"); char aCurrentTimestamp[512]; pSqlServer->ToUnixTimestamp("CURRENT_TIMESTAMP", aCurrentTimestamp, sizeof(aCurrentTimestamp)); @@ -876,12 +876,12 @@ bool CScoreWorker::ShowTeamRank(IDbConnection *pSqlServer, const ISqlData *pGame char aFormattedNames[512] = ""; for(unsigned int Name = 0; Name < Teamrank.m_NumNames; Name++) { - str_append(aFormattedNames, Teamrank.m_aaNames[Name], sizeof(aFormattedNames)); + str_append(aFormattedNames, Teamrank.m_aaNames[Name]); if(Name < Teamrank.m_NumNames - 2) - str_append(aFormattedNames, ", ", sizeof(aFormattedNames)); + str_append(aFormattedNames, ", "); else if(Name < Teamrank.m_NumNames - 1) - str_append(aFormattedNames, " & ", sizeof(aFormattedNames)); + str_append(aFormattedNames, " & "); } if(g_Config.m_SvHideScore) @@ -1051,11 +1051,11 @@ bool CScoreWorker::ShowTeamTop5(IDbConnection *pSqlServer, const ISqlData *pGame { char aName[MAX_NAME_LENGTH]; pSqlServer->GetString(1, aName, sizeof(aName)); - str_append(aNames, aName, sizeof(aNames)); + str_append(aNames, aName); if(i < TeamSize - 2) - str_append(aNames, ", ", sizeof(aNames)); + str_append(aNames, ", "); else if(i == TeamSize - 2) - str_append(aNames, " & ", sizeof(aNames)); + str_append(aNames, " & "); if(pSqlServer->Step(&Last, pError, ErrorSize)) { return true; @@ -1143,12 +1143,12 @@ bool CScoreWorker::ShowPlayerTeamTop5(IDbConnection *pSqlServer, const ISqlData char aFormattedNames[512] = ""; for(unsigned int Name = 0; Name < Teamrank.m_NumNames; Name++) { - str_append(aFormattedNames, Teamrank.m_aaNames[Name], sizeof(aFormattedNames)); + str_append(aFormattedNames, Teamrank.m_aaNames[Name]); if(Name < Teamrank.m_NumNames - 2) - str_append(aFormattedNames, ", ", sizeof(aFormattedNames)); + str_append(aFormattedNames, ", "); else if(Name < Teamrank.m_NumNames - 1) - str_append(aFormattedNames, " & ", sizeof(aFormattedNames)); + str_append(aFormattedNames, " & "); } str_format(paMessages[Line], sizeof(paMessages[Line]), "%d. %s Team Time: %s", @@ -1776,11 +1776,11 @@ bool CScoreWorker::GetSaves(IDbConnection *pSqlServer, const ISqlData *pGameData auto *paMessages = pResult->m_Data.m_aaMessages; char aSaveLike[128] = ""; - str_append(aSaveLike, "%\n", sizeof(aSaveLike)); + str_append(aSaveLike, "%\n"); sqlstr::EscapeLike(aSaveLike + str_length(aSaveLike), pData->m_aRequestingPlayer, sizeof(aSaveLike) - str_length(aSaveLike)); - str_append(aSaveLike, "\t%", sizeof(aSaveLike)); + str_append(aSaveLike, "\t%"); char aCurrentTimestamp[512]; pSqlServer->ToUnixTimestamp("CURRENT_TIMESTAMP", aCurrentTimestamp, sizeof(aCurrentTimestamp)); diff --git a/src/game/server/teams.cpp b/src/game/server/teams.cpp index 62ea86bc1..b4f8850d1 100644 --- a/src/game/server/teams.cpp +++ b/src/game/server/teams.cpp @@ -161,9 +161,9 @@ void CGameTeams::OnCharacterStart(int ClientID) if(First) First = false; else - str_append(aBuf, ", ", sizeof(aBuf)); + str_append(aBuf, ", "); - str_append(aBuf, GameServer()->Server()->ClientName(i), sizeof(aBuf)); + str_append(aBuf, GameServer()->Server()->ClientName(i)); } } } @@ -270,9 +270,9 @@ void CGameTeams::Tick() { if(aPlayerNames[0]) { - str_append(aPlayerNames, ", ", sizeof(aPlayerNames)); + str_append(aPlayerNames, ", "); } - str_append(aPlayerNames, Server()->ClientName(j), sizeof(aPlayerNames)); + str_append(aPlayerNames, Server()->ClientName(j)); NumPlayersNotStarted += 1; } } diff --git a/src/tools/config_common.h b/src/tools/config_common.h index 992e3b85f..500e214d6 100644 --- a/src/tools/config_common.h +++ b/src/tools/config_common.h @@ -27,7 +27,7 @@ inline void ProcessItem(const char *pItemName, IStorage *pStorage) str_copy(aConfig, pItemName, sizeof(aConfig)); aConfig[Len - sizeof(".map")] = 0; - str_append(aConfig, ".cfg", sizeof(aConfig)); + str_append(aConfig, ".cfg"); dbg_msg("config_common", "processing '%s'", pItemName); Process(pStorage, pItemName, aConfig); } From 410ccda1c7d98c56f34c14ff7e99dbe0ed7c97f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Tue, 13 Jun 2023 21:08:59 +0200 Subject: [PATCH 2/4] Move templated `str_copy` next to basic function The functions were only separated because we previously had a large `extern "C"` block. --- src/base/system.h | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/base/system.h b/src/base/system.h index 7ec1b2ee9..e4482f71f 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -1227,6 +1227,23 @@ void str_append(char (&dst)[N], const char *src) */ int str_copy(char *dst, const char *src, int dst_size); +/** + * Copies a string to a fixed-size array of chars. + * + * @ingroup Strings + * + * @param dst Array that shall receive the string. + * @param src String to be copied. + * + * @remark The strings are treated as zero-terminated strings. + * @remark Guarantees that dst string will contain zero-termination. + */ +template +void str_copy(char (&dst)[N], const char *src) +{ + str_copy(dst, src, N); +} + /** * Truncates a utf8 encoded string to a given length. * @@ -2797,23 +2814,6 @@ bool shell_unregister_application(const char *executable, bool *updated); void shell_update(); #endif -/** - * Copies a string to a fixed-size array of chars. - * - * @ingroup Strings - * - * @param dst Array that shall receive the string. - * @param src String to be copied. - * - * @remark The strings are treated as zero-terminated strings. - * @remark Guarantees that dst string will contain zero-termination. - */ -template -void str_copy(char (&dst)[N], const char *src) -{ - str_copy(dst, src, N); -} - template<> struct std::hash { From 3069733b863c858bccb4116e90fb1acfd0025b6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Wed, 14 Jun 2023 00:03:30 +0200 Subject: [PATCH 3/4] Add tests for `str_append` and for templated `str_copy` --- src/test/str.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/test/str.cpp b/src/test/str.cpp index 2c13d3baa..5202c07a5 100644 --- a/src/test/str.cpp +++ b/src/test/str.cpp @@ -586,6 +586,37 @@ TEST(Str, Copy) EXPECT_STREQ(aBuf, "DDNet最好了"); str_copy(aBuf, pStr, 16); EXPECT_STREQ(aBuf, "DDNet最好了"); + str_copy(aBuf, pStr); + EXPECT_STREQ(aBuf, "DDNet最好了"); +} + +TEST(Str, Append) +{ + char aBuf[64]; + aBuf[0] = '\0'; + str_append(aBuf, "DDNet最好了", 7); + EXPECT_STREQ(aBuf, "DDNet"); + str_append(aBuf, "最", 8); + EXPECT_STREQ(aBuf, "DDNet"); + str_append(aBuf, "最", 9); + EXPECT_STREQ(aBuf, "DDNet最"); + str_append(aBuf, "好", 10); + EXPECT_STREQ(aBuf, "DDNet最"); + str_append(aBuf, "好", 11); + EXPECT_STREQ(aBuf, "DDNet最"); + str_append(aBuf, "好", 12); + EXPECT_STREQ(aBuf, "DDNet最好"); + str_append(aBuf, "了", 13); + EXPECT_STREQ(aBuf, "DDNet最好"); + str_append(aBuf, "了", 14); + EXPECT_STREQ(aBuf, "DDNet最好"); + str_append(aBuf, "了", 15); + EXPECT_STREQ(aBuf, "DDNet最好了"); + str_append(aBuf, "了", 16); + EXPECT_STREQ(aBuf, "DDNet最好了"); + aBuf[0] = '\0'; + str_append(aBuf, "DDNet最好了"); + EXPECT_STREQ(aBuf, "DDNet最好了"); } TEST(Str, Utf8Stats) From 3ad581aeb8e139268fa2e99dabea43a72d44adcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Tue, 13 Jun 2023 21:09:26 +0200 Subject: [PATCH 4/4] Ensure proper buffer size is used with DDNet server filter By passing the buffer size when calling `DDNetFilterAdd` and `DDNetFilterRem`. Mark functions and pointer parameters as `const`. --- src/engine/client/serverbrowser.cpp | 14 +++++++------- src/engine/client/serverbrowser.h | 6 +++--- src/engine/serverbrowser.h | 6 +++--- src/game/client/components/menus_browser.cpp | 14 ++++++++------ 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/engine/client/serverbrowser.cpp b/src/engine/client/serverbrowser.cpp index e4144c644..1b5d1647e 100644 --- a/src/engine/client/serverbrowser.cpp +++ b/src/engine/client/serverbrowser.cpp @@ -1415,17 +1415,17 @@ int CServerBrowser::LoadingProgression() const return 100.0f * Loaded / Servers; } -void CServerBrowser::DDNetFilterAdd(char *pFilter, const char *pName) +void CServerBrowser::DDNetFilterAdd(char *pFilter, int FilterSize, const char *pName) const { if(DDNetFiltered(pFilter, pName)) return; char aBuf[128]; str_format(aBuf, sizeof(aBuf), ",%s", pName); - str_append(pFilter, aBuf, 128); + str_append(pFilter, aBuf, FilterSize); } -void CServerBrowser::DDNetFilterRem(char *pFilter, const char *pName) +void CServerBrowser::DDNetFilterRem(char *pFilter, int FilterSize, const char *pName) const { if(!DDNetFiltered(pFilter, pName)) return; @@ -1443,12 +1443,12 @@ void CServerBrowser::DDNetFilterRem(char *pFilter, const char *pName) { char aBuf2[128]; str_format(aBuf2, sizeof(aBuf2), ",%s", aToken); - str_append(pFilter, aBuf2, 128); + str_append(pFilter, aBuf2, FilterSize); } } } -bool CServerBrowser::DDNetFiltered(char *pFilter, const char *pName) +bool CServerBrowser::DDNetFiltered(const char *pFilter, const char *pName) const { return str_in_list(pFilter, ",", pName); // country not excluded } @@ -1468,7 +1468,7 @@ void CServerBrowser::CountryFilterClean(int Network) { char aBuf[128]; str_format(aBuf, sizeof(aBuf), ",%s", pName); - str_append(aNewList, aBuf, sizeof(aNewList)); + str_append(aNewList, aBuf); } } } @@ -1489,7 +1489,7 @@ void CServerBrowser::TypeFilterClean(int Network) { char aBuf[128]; str_format(aBuf, sizeof(aBuf), ",%s", pName); - str_append(aNewList, aBuf, sizeof(aNewList)); + str_append(aNewList, aBuf); } } diff --git a/src/engine/client/serverbrowser.h b/src/engine/client/serverbrowser.h index 73b290765..272b4d402 100644 --- a/src/engine/client/serverbrowser.h +++ b/src/engine/client/serverbrowser.h @@ -114,9 +114,9 @@ public: int NumTypes(int Network) override { return m_aNetworks[Network].m_NumTypes; } const char *GetType(int Network, int Index) override { return m_aNetworks[Network].m_aTypes[Index]; } - void DDNetFilterAdd(char *pFilter, const char *pName) override; - void DDNetFilterRem(char *pFilter, const char *pName) override; - bool DDNetFiltered(char *pFilter, const char *pName) override; + void DDNetFilterAdd(char *pFilter, int FilterSize, const char *pName) const override; + void DDNetFilterRem(char *pFilter, int FilterSize, const char *pName) const override; + bool DDNetFiltered(const char *pFilter, const char *pName) const override; void CountryFilterClean(int Network) override; void TypeFilterClean(int Network) override; diff --git a/src/engine/serverbrowser.h b/src/engine/serverbrowser.h index 3ac6d39b3..28ccf2e45 100644 --- a/src/engine/serverbrowser.h +++ b/src/engine/serverbrowser.h @@ -165,9 +165,9 @@ public: virtual int NumTypes(int Network) = 0; virtual const char *GetType(int Network, int Index) = 0; - virtual void DDNetFilterAdd(char *pFilter, const char *pName) = 0; - virtual void DDNetFilterRem(char *pFilter, const char *pName) = 0; - virtual bool DDNetFiltered(char *pFilter, const char *pName) = 0; + virtual void DDNetFilterAdd(char *pFilter, int FilterSize, const char *pName) const = 0; + virtual void DDNetFilterRem(char *pFilter, int FilterSize, const char *pName) const = 0; + virtual bool DDNetFiltered(const char *pFilter, const char *pName) const = 0; virtual void CountryFilterClean(int Network) = 0; virtual void TypeFilterClean(int Network) = 0; virtual int GetCurrentType() = 0; diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp index 0e464ad97..bd1d5d1af 100644 --- a/src/game/client/components/menus_browser.cpp +++ b/src/game/client/components/menus_browser.cpp @@ -762,6 +762,7 @@ void CMenus::RenderServerbrowserFilters(CUIRect View) if(s_ActivePage == 1) { char *pFilterExcludeTypes = Network == IServerBrowser::NETWORK_DDNET ? g_Config.m_BrFilterExcludeTypes : g_Config.m_BrFilterExcludeTypesKoG; + const int FilterExcludeTypesSize = Network == IServerBrowser::NETWORK_DDNET ? sizeof(g_Config.m_BrFilterExcludeTypes) : sizeof(g_Config.m_BrFilterExcludeTypesKoG); int MaxTypes = ServerBrowser()->NumTypes(Network); int NumTypes = ServerBrowser()->NumTypes(Network); int PerLine = 3; @@ -811,7 +812,7 @@ void CMenus::RenderServerbrowserFilters(CUIRect View) for(int j = 0; j < MaxTypes; ++j) { if(j != TypeIndex) - ServerBrowser()->DDNetFilterAdd(pFilterExcludeTypes, ServerBrowser()->GetType(Network, j)); + ServerBrowser()->DDNetFilterAdd(pFilterExcludeTypes, FilterExcludeTypesSize, ServerBrowser()->GetType(Network, j)); } } else @@ -832,11 +833,11 @@ void CMenus::RenderServerbrowserFilters(CUIRect View) } else if(Active) { - ServerBrowser()->DDNetFilterAdd(pFilterExcludeTypes, pName); + ServerBrowser()->DDNetFilterAdd(pFilterExcludeTypes, FilterExcludeTypesSize, pName); } else { - ServerBrowser()->DDNetFilterRem(pFilterExcludeTypes, pName); + ServerBrowser()->DDNetFilterRem(pFilterExcludeTypes, FilterExcludeTypesSize, pName); } } @@ -858,6 +859,7 @@ void CMenus::RenderServerbrowserFilters(CUIRect View) else { char *pFilterExcludeCountries = Network == IServerBrowser::NETWORK_DDNET ? g_Config.m_BrFilterExcludeCountries : g_Config.m_BrFilterExcludeCountriesKoG; + const int FilterExcludeCountriesSize = Network == IServerBrowser::NETWORK_DDNET ? sizeof(g_Config.m_BrFilterExcludeCountries) : sizeof(g_Config.m_BrFilterExcludeCountriesKoG); ServerFilter.HSplitTop(15.0f, &ServerFilter, &ServerFilter); const float FlagWidth = 40.0f; @@ -907,7 +909,7 @@ void CMenus::RenderServerbrowserFilters(CUIRect View) for(int j = 0; j < MaxFlags; ++j) { if(j != CountryIndex) - ServerBrowser()->DDNetFilterAdd(pFilterExcludeCountries, ServerBrowser()->GetCountryName(Network, j)); + ServerBrowser()->DDNetFilterAdd(pFilterExcludeCountries, FilterExcludeCountriesSize, ServerBrowser()->GetCountryName(Network, j)); } } else @@ -928,11 +930,11 @@ void CMenus::RenderServerbrowserFilters(CUIRect View) } else if(Active) { - ServerBrowser()->DDNetFilterAdd(pFilterExcludeCountries, pName); + ServerBrowser()->DDNetFilterAdd(pFilterExcludeCountries, FilterExcludeCountriesSize, pName); } else { - ServerBrowser()->DDNetFilterRem(pFilterExcludeCountries, pName); + ServerBrowser()->DDNetFilterRem(pFilterExcludeCountries, FilterExcludeCountriesSize, pName); } }