String safety (#1548)

* Array size UB fixes

* Fix ShieldD

* Remove (almost) all unsafe strcpy calls

Bunch of macros. C arrays are easy enough and just need a different call. For various cases where a char* is passed around bare, I've made a TEXT_SPAN macro that can store a length too for bounds checking.

* Move crash handling in safe string operations to separate TU

* strcat safe version

* sprintf made safe too

* Fix compile
This commit is contained in:
Pieter-Jan Briers
2026-05-24 18:43:00 +02:00
committed by GitHub
parent af162bbd0a
commit a6376368ee
100 changed files with 781 additions and 546 deletions
+85
View File
@@ -0,0 +1,85 @@
#include "dusk/string.hpp"
#include "fmt/format.h"
namespace {
void strncpyProxy(char* dst, const char* src, size_t count) {
#if _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
strncpy(dst, src, count);
#if _MSC_VER
#pragma warning(pop)
#endif
}
} // namespace
namespace dusk {
void TextSpan::CrashSpawnEmpty() {
CRASH("Span is empty!");
}
void SafeStringCopyTruncate(char* buffer, size_t bufSize, const char* src) {
if (buffer == src) [[unlikely]] {
CRASH("Cannot copy string to same buffer");
}
if (bufSize == 0) [[unlikely]] {
CRASH("Target buffer cannot be size zero");
}
strncpyProxy(buffer, src, bufSize);
buffer[bufSize - 1] = 0;
}
void SafeStringCopy(char* buffer, size_t bufSize, const char* src) {
if (bufSize == 0) [[unlikely]] {
CRASH("Target buffer cannot be size zero");
}
if (buffer == src) [[unlikely]] {
CRASH("Cannot copy string to same buffer");
}
const auto srcSize = strlen(src);
if (srcSize > bufSize - 1) [[unlikely]] {
const auto msg = fmt::format(
"Destination buffer too small! Need %d, have %d",
srcSize + 1,
bufSize);
CRASH("%s", msg.c_str());
}
strncpyProxy(buffer, src, bufSize);
buffer[bufSize - 1] = 0;
}
void SafeStringCat(char* buffer, size_t bufSize, const char* src) {
if (bufSize == 0) [[unlikely]] {
CRASH("Target buffer cannot be size zero");
}
if (buffer == src) [[unlikely]] {
CRASH("Cannot copy string to same buffer");
}
const auto dstSize = strnlen(buffer, bufSize);
const auto srcSize = strlen(src);
if (dstSize + srcSize + 1 > bufSize) [[unlikely]] {
CRASH("Destination buffer too small!");
}
memcpy(buffer + dstSize, src, srcSize);
buffer[dstSize + srcSize] = 0;
}
int SafeStringVPrintf(char* buffer, size_t bufSize, const char* src, std::va_list args) {
if (bufSize == 0) [[unlikely]] {
CRASH("Target buffer cannot be size zero");
}
return vsnprintf(buffer, bufSize, src, args);
}
} // namespace dusk