From c2db2d8d45d0802ed8807f4e33b6c2ec89ef7468 Mon Sep 17 00:00:00 2001 From: Leonardo Zide Date: Mon, 15 Dec 2025 11:19:23 -0300 Subject: [PATCH] Added bounds check to strcat. --- common/lc_library.cpp | 4 ++-- common/lc_model.cpp | 2 +- common/lc_string.cpp | 41 ++++++++++++++++++++++++++++++++++++----- common/lc_string.h | 9 ++++++++- common/piece.cpp | 3 ++- common/project.cpp | 2 +- 6 files changed, 50 insertions(+), 11 deletions(-) diff --git a/common/lc_library.cpp b/common/lc_library.cpp index fdf20d64..68775054 100644 --- a/common/lc_library.cpp +++ b/common/lc_library.cpp @@ -1668,7 +1668,7 @@ bool lcPiecesLibrary::LoadPrimitive(lcLibraryPrimitive* Primitive) { char Name[LC_PIECE_NAME_LEN]; lcstrcpy(Name, "8/"); - strcat(Name, Primitive->mName); + lcstrcat(Name, Primitive->mName); lcstrupr(Name); LowPrimitive = FindPrimitive(Name); // todo: low primitives don't work with studlogo, because the low stud gets added as shared @@ -1770,7 +1770,7 @@ void lcPiecesLibrary::GetCategoryEntries(const char* CategoryKeywords, bool Grou char ParentName[LC_PIECE_NAME_LEN]; lcstrcpy(ParentName, Info->mFileName); *strchr(ParentName, 'P') = '\0'; - strcat(ParentName, ".dat"); + lcstrcat(ParentName, ".dat"); Parent = FindPiece(ParentName, nullptr, false, false); diff --git a/common/lc_model.cpp b/common/lc_model.cpp index dff17fb8..47b9b8ea 100644 --- a/common/lc_model.cpp +++ b/common/lc_model.cpp @@ -850,7 +850,7 @@ bool lcModel::LoadBinary(lcFile* file) file->ReadFloats(rot.GetFloats(), 3); file->ReadU8(&color, 1); file->ReadBuffer(name, 9); - strcat(name, ".dat"); + lcstrcat(name, ".dat"); file->ReadU8(&step, 1); file->ReadU8(&group, 1); diff --git a/common/lc_string.cpp b/common/lc_string.cpp index dcc8546e..0e5cfa57 100644 --- a/common/lc_string.cpp +++ b/common/lc_string.cpp @@ -30,12 +30,12 @@ char* lcstrupr(char* string) return string; } -size_t lcstrcpy(char* dest, const char* source, size_t count) +size_t lcstrcpy(char* dest, const char* source, size_t size) { - if (count == 0) + if (size == 0) return 0; - for (size_t i = 0; i < count; i++) + for (size_t i = 0; i < size; i++) { dest[i] = source[i]; @@ -45,7 +45,38 @@ size_t lcstrcpy(char* dest, const char* source, size_t count) } } - dest[--count] = '\0'; + dest[--size] = '\0'; - return count; + return size; +} + +size_t lcstrcat(char* dest, const char* source, size_t size) +{ + char* d = dest; + const char* s = source; + size_t n = size; + size_t dlen; + + while (n-- != 0 && *d != '\0') + d++; + + dlen = d - dest; + n = size - dlen; + + if (n == 0) + return(dlen + strlen(s)); + + while (*s != '\0') + { + if (n != 1) + { + *d++ = *s; + n--; + } + s++; + } + + *d = '\0'; + + return (dlen + (s - source)); } diff --git a/common/lc_string.h b/common/lc_string.h index 3d4cdbdd..2117b8a7 100644 --- a/common/lc_string.h +++ b/common/lc_string.h @@ -2,10 +2,17 @@ char* lcstrcasestr(const char* s, const char* find); char* lcstrupr(char* string); -size_t lcstrcpy(char* dest, const char* source, size_t count); +size_t lcstrcpy(char* dest, const char* source, size_t size); +size_t lcstrcat(char* dest, const char* source, size_t size); template size_t lcstrcpy(char (&dest)[size], const char* source) { return lcstrcpy(dest, source, size); } + +template +size_t lcstrcat(char (&dest)[size], const char* source) +{ + return lcstrcat(dest, source, size); +} diff --git a/common/piece.cpp b/common/piece.cpp index 5bc6848a..842c29e6 100644 --- a/common/piece.cpp +++ b/common/piece.cpp @@ -15,6 +15,7 @@ #include "lc_qutils.h" #include "lc_synth.h" #include "lc_traintrack.h" +#include "lc_string.h" constexpr float LC_PIECE_CONTROL_POINT_SIZE = 10.0f; @@ -336,7 +337,7 @@ bool lcPiece::FileLoad(lcFile& file) } else file.ReadBuffer(name, LC_PIECE_NAME_LEN); - strcat(name, ".dat"); + lcstrcat(name, ".dat"); PieceInfo* pInfo = lcGetPiecesLibrary()->FindPiece(name, nullptr, true, false); SetPieceInfo(pInfo, QString(), true, true); diff --git a/common/project.cpp b/common/project.cpp index 3d168caf..0b2eecf8 100644 --- a/common/project.cpp +++ b/common/project.cpp @@ -2239,7 +2239,7 @@ std::pair Project::ExportPOVRay(const QString& FileName) if (sscanf(Line,"%128s%128s%10s", Src, Dst, Flags) != 3) continue; - strcat(Src, ".dat"); + lcstrcat(Src, ".dat"); PieceInfo* Info = Library->FindPiece(Src, nullptr, false, false); if (!Info)