带可变参数的C函数outputDebug崩溃问题排查求助
Debug Function Crash: Root Cause & Fix
Let's break down why your outputDebug function is crashing and fix it step by step.
Critical Bug Causing the Crash
Your call to vsprintf_s is the main culprit here:
- You’re passing
"%s"as the format string, which only expects one string argument (szPrefix), but you’re also appending theva_list apafterward. This mismatched parameter count triggers undefined behavior—almost certainly the crash you’re seeing due to invalid memory access. - Worse,
szPrefixalready includes the format placeholders fromcpszFormat(like%sin your example call). You need to useszPrefixdirectly as the format string forvsprintf_s, not"%s".
Additional Potential Issues to Address
- Type Mismatch in Format Specifier:
uintLineNois anunsignedtype, but you’re using%05ld(for signed long integers). This can cause incorrect output or unexpected behavior. Switch to%05u(for unsigned int) instead. - Buffer Overflow Risk:
szPrefix(80 bytes) andszOut(256 bytes) are small. If your formatted string plus date/time/line info exceeds these limits,sprintf_s/vsprintf_swill throw an error or crash. We’ll adjust this for safety.
Fixed Version of the Function
Here’s the corrected code with clear improvements:
static void outputDebug(unsigned uintLineNo, const char* cpszFormat, ...) { // Expand buffer sizes to handle longer strings safely char szPrefix[128], szOut[512]; va_list ap; va_start(ap, cpszFormat); // Fix format specifier for unsigned line number (%05u) sprintf_s(szPrefix, sizeof(szPrefix), "%s %s %05u: %s", __DATE__, __TIME__, uintLineNo, cpszFormat); // Use szPrefix as the format string, and pass va_list to fill placeholders vsprintf_s(szOut, sizeof(szOut), szPrefix, ap); va_end(ap); OutputDebugString(szOut); }
Even Safer Version (Eliminate Buffer Limits)
To completely remove buffer overflow risks, calculate the required memory dynamically:
#include <stdlib.h> // For malloc/free static void outputDebug(unsigned uintLineNo, const char* cpszFormat, ...) { char* szOut = NULL; va_list ap, apCopy; int prefixLen, totalLen; // Calculate length of the prefix string prefixLen = sprintf_s(NULL, 0, "%s %s %05u: %s", __DATE__, __TIME__, uintLineNo, cpszFormat); if (prefixLen < 0) return; // Handle formatting error // Initialize va_list to calculate total needed length va_start(ap, cpszFormat); va_copy(apCopy, ap); // Make a copy since va_start can only be used once for calculation // Calculate total length including formatted arguments totalLen = _vscprintf_s(cpszFormat, apCopy) + prefixLen; va_end(apCopy); // Allocate buffer (add 1 for null terminator) szOut = (char*)malloc(totalLen + 1); if (szOut == NULL) { va_end(ap); return; // Handle allocation failure } // Build the full formatted string sprintf_s(szOut, totalLen + 1, "%s %s %05u: %s", __DATE__, __TIME__, uintLineNo, cpszFormat); vsprintf_s(szOut + prefixLen, totalLen - prefixLen + 1, cpszFormat, ap); va_end(ap); OutputDebugString(szOut); free(szOut); // Clean up allocated memory }
Why This Fix Works
- The
vsprintf_scall now usesszPrefix(which includes your original format string) as the format specifier, correctly passing theva_listto fill in placeholders fromcpszFormat. - Fixed the type mismatch for the line number to ensure proper formatting.
- The safer version calculates exactly how much memory is needed, eliminating any risk of buffer overflow.
内容的提问来源于stack exchange,提问作者SPlatten
相关产品推荐
相关产品推荐

