diff --git a/include/dusk/string.hpp b/include/dusk/string.hpp new file mode 100644 index 0000000000..f1a365ebbb --- /dev/null +++ b/include/dusk/string.hpp @@ -0,0 +1,52 @@ +#ifndef DUSK_STRING_HPP +#define DUSK_STRING_HPP + +#include "global.h" +#include +#include + +namespace dusk { + +/** + * Copy a string to a fixed-size array. + * Truncates if the destination is not large enough, always inserts a null terminator (padding the remainder of the buffer with zeroes.) + */ +template +void SafeStringCopyTruncate(char (&buffer)[BufSize], const char* src) { + static_assert(BufSize > 0, "Target buffer cannot be size zero"); + + // Can't just use strncpy as I can't figure out how to selectively mute the warnings on MSVC. + // And can't use strncpy_s on MSVC as it doesn't fill the entire buffer. + constexpr size_t copyBufSize = BufSize - 1; + const auto srcLen = strlen(src); + const auto copyLen = srcLen > copyBufSize ? copyBufSize : srcLen; + memcpy(buffer, src, copyLen); + memset(buffer + copyLen, 0, BufSize - copyLen); +} + +/** + * Copy a string to a fixed-size array. + * Aborts if the destination is not large enough, always inserts a null terminator (padding the remainder of the buffer with zeroes.) + */ +template +void SafeStringCopy(char (&buffer)[BufSize], const char* src) { + static_assert(BufSize > 0, "Target buffer cannot be size zero"); + if (buffer == src) { + CRASH("Cannot copy string to same buffer"); + } + + // Can't just use strncpy as I can't figure out how to selectively mute the warnings on MSVC. + // And can't use strncpy_s on MSVC as it doesn't fill the entire buffer. + constexpr size_t copyBufSize = BufSize - 1; + const auto srcLen = strlen(src); + if (srcLen > copyBufSize) { + CRASH("Destination buffer too small!"); + } + + memcpy(buffer, src, srcLen); + memset(buffer + srcLen, 0, BufSize - srcLen); +} + +} + +#endif // DUSK_STRING_HPP diff --git a/libs/JSystem/src/JKernel/JKRHeap.cpp b/libs/JSystem/src/JKernel/JKRHeap.cpp index c2b32999fd..ce1899a4ba 100644 --- a/libs/JSystem/src/JKernel/JKRHeap.cpp +++ b/libs/JSystem/src/JKernel/JKRHeap.cpp @@ -15,6 +15,7 @@ #include "JSystem/JUtility/JUTAssert.h" #include "JSystem/JUtility/JUTException.h" +#include "dusk/string.hpp" #ifdef __MWERKS__ #include #else @@ -701,9 +702,7 @@ JKRHeap* JKRHeap::getCurrentHeap() { } void JKRHeap::setName(const char* name) { - size_t len = strlen(name); - strncpy(mName, name, sizeof(mName) - 1); - mName[sizeof(mName) - 1] = '\0'; + dusk::SafeStringCopyTruncate(mName, name); } void JKRHeap::setNamef(const char* fmt, ...) { diff --git a/src/d/d_stage.cpp b/src/d/d_stage.cpp index 9ada8b57b6..4d8c531b3c 100644 --- a/src/d/d_stage.cpp +++ b/src/d/d_stage.cpp @@ -21,6 +21,8 @@ #include "m_Do/m_Do_Reset.h" #include #include + +#include "dusk/string.hpp" #if TARGET_PC #include #include @@ -154,7 +156,7 @@ void dStage_startStage_c::set(const char* i_Name, s8 i_RoomNo, s16 i_Point, s8 i #if TARGET_PC // UB fix. if (mName != i_Name) { - strncpy_s(mName, sizeof(mName), i_Name, sizeof(mName)); + dusk::SafeStringCopy(mName, i_Name); } #else strcpy(mName, i_Name);