From 70b86c2281e77f378d42916e5a61d8ad64c517b1 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Sun, 31 May 2026 19:49:48 -0700 Subject: [PATCH] Use va_copy in v1 LogF macro before sizing pass The LogF macro starts a single va_list, passes it to _vscprintf / _vscwprintf to size the buffer, and then reuses the same va_list for vsnprintf_s / _vsnwprintf_s. Per the C standard, a va_list is in an indeterminate state after a vararg consumer reads from it, and any further use without va_copy or a fresh va_start is undefined behavior. This happens to work on MSVC x64 today because va_list is effectively a char* there. It will not work on ARM64, on a future MSVC that changes the representation, or on plugins built against a CRT with stricter va_list semantics. Since this is the entire formatted- logging surface for v1 plugins, getting it wrong breaks every plugin's logger at once. Copy args into a second va_list for the count_fn call and end that copy immediately, leaving the original args intact for format_fn. Fixes #135 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/dll/v1/Logger.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/dll/v1/Logger.cpp b/src/dll/v1/Logger.cpp index c8a0c000..a5367479 100644 --- a/src/dll/v1/Logger.cpp +++ b/src/dll/v1/Logger.cpp @@ -53,7 +53,10 @@ va_list args; \ va_start(args, aFormat); \ \ - auto len = count_fn(aFormat, args); \ + va_list argsForLen; \ + va_copy(argsForLen, args); \ + auto len = count_fn(aFormat, argsForLen); \ + va_end(argsForLen); \ if (len > 0) \ { \ std::vector buffer(len + 1); /* len + NULL character. */ \