@@ -418,18 +418,27 @@ namespace loguru
418418 LOGURU_PRINTF_LIKE (1 , 0 )
419419 static Text vtextprintf(const char * format, va_list vlist)
420420 {
421- #ifdef _WIN32
422- int bytes_needed = _vscprintf (format, vlist);
421+ // Determine the required length of the string
422+ int bytes_needed = 0 ;
423+
424+ // Calling vsnprintf is assumed to 'consume' the vlist, therefore we need a copy
425+ // of the args to avoid corrupting the stack in the second call to vsnprintf.
426+ va_list argcopy;
427+ va_copy (argcopy, vlist);
428+ bytes_needed = vsnprintf (NULL , 0 , format, argcopy);
429+ va_end (argcopy);
423430 CHECK_F (bytes_needed >= 0 , " Bad string format: '%s'" , format);
424- char * buff = (char *)malloc (bytes_needed+1 );
425- vsnprintf (buff, bytes_needed+1 , format, vlist);
426- return Text (buff);
427- #else
428- char * buff = nullptr ;
429- int result = vasprintf (&buff, format, vlist);
430- CHECK_F (result >= 0 , " Bad string format: '" LOGURU_FMT (s) " '" , format);
431+
432+ // Allocate the string's buffer
433+ ++bytes_needed; // Add space for null terminator
434+ auto buff = static_cast <char *>(malloc (bytes_needed));
435+ CHECK_F (buff != nullptr , " Out of memory" );
436+
437+ // Construct the string and check the result
438+ const auto written = vsnprintf (buff, bytes_needed, format, vlist);
439+ CHECK_F (written <= bytes_needed, " Bad string format: '%s'" , format);
440+
431441 return Text (buff);
432- #endif
433442 }
434443
435444 Text textprintf (const char * format, ...)
0 commit comments