diff --git a/src/Components/Modules/Threading.cpp b/src/Components/Modules/Threading.cpp index 2288dd90..72e11a5a 100644 --- a/src/Components/Modules/Threading.cpp +++ b/src/Components/Modules/Threading.cpp @@ -43,5 +43,8 @@ namespace Components Utils::Hook(0x627695, 0x627040, HOOK_CALL).install()->quick(); Utils::Hook(0x43D1C7, Threading::PacketEventStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x6272E3, Threading::FrameEpilogueStub, HOOK_JUMP).install()->quick(); + + // Make VA thread safe + Utils::Hook(0x4785B0, Utils::String::VA, HOOK_JUMP).install()->quick(); } } diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index 0ce7a9df..b81bb7d1 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -3,25 +3,51 @@ #include "base128.h" #endif -#define VA_BUFFER_COUNT 32 -#define VA_BUFFER_SIZE 65536 - namespace Utils { namespace String { + VAProvider::VAProvider(size_t buffers) : currentBuffer(0) + { + this->stringBuffers.resize(buffers); + } + + char* VAProvider::get(const char* format, va_list ap) + { + ++this->currentBuffer %= this->stringBuffers.size(); + auto& buffer = this->stringBuffers[this->currentBuffer]; + + if (!buffer.first || !buffer.second) + { + buffer.first = 256; + if (buffer.second) this->allocator.free(buffer.second); + buffer.second = this->allocator.allocateArray(buffer.first + 1); + } + + while(true) + { + int res = vsnprintf_s(buffer.second, buffer.first, _TRUNCATE, format, ap); + if (res > 0) break; // Success + if (res == 0) return ""; // Error + + buffer.first *= 2; + + this->allocator.free(buffer.second); + buffer.second = this->allocator.allocateArray(buffer.first + 1); + } + + return buffer.second; + } + const char *VA(const char *fmt, ...) { - static char g_vaBuffer[VA_BUFFER_COUNT][VA_BUFFER_SIZE]; - static int g_vaNextBufferIndex = 0; + static thread_local VAProvider provider; va_list ap; va_start(ap, fmt); - char* dest = g_vaBuffer[g_vaNextBufferIndex]; - vsnprintf_s(g_vaBuffer[g_vaNextBufferIndex], VA_BUFFER_SIZE, fmt, ap); - g_vaNextBufferIndex = (g_vaNextBufferIndex + 1) % VA_BUFFER_COUNT; + const char* result = provider.get(fmt, ap); va_end(ap); - return dest; + return result; } std::string ToLower(std::string input) diff --git a/src/Utils/String.hpp b/src/Utils/String.hpp index f1720504..00b4a07e 100644 --- a/src/Utils/String.hpp +++ b/src/Utils/String.hpp @@ -4,6 +4,20 @@ namespace Utils { namespace String { + class VAProvider + { + public: + VAProvider(size_t buffers = 8); + + char* get(const char* format, va_list ap); + + private: + size_t currentBuffer; + std::vector> stringBuffers; + + Utils::Memory::Allocator allocator; + }; + const char *VA(const char *fmt, ...); int IsSpace(int c);