You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用NULL目标指针调用vsnprintf返回意外值的问题排查

Why Your SAFE_snprintf Is Returning an Unexpected vsnprintf Result

Let's break down the two key issues causing that mismatched m = 10 value instead of the expected 7:

1. You're Reusing a Consumed va_list

Here's the critical problem: when you initialize a va_list with va_start(args, format), it points to the first variable argument in your function call. Functions like vsnprintf advance this pointer as they process each argument. Once you've run vsnprintf once with args, that list is used up—it no longer points to the start of your input arguments.

When you call vsnprintf a second time with the same args without resetting it, you're reading memory beyond your actual input values. This is undefined behavior, which explains the incorrect length value you're seeing.

To fix this, you have two straightforward options:

  • Use va_copy to create a duplicate of the original va_list before your first vsnprintf call, then use the copy for the second formatting step.
  • Or, call va_end(args) after the first vsnprintf, then re-run va_start(args, format) to reset the list before the second call.

2. You're Using an Undefined Variable n

Looking at your SAFE_snprintf code, you reference a variable n that doesn't exist in the function's scope. This is a compile error (unless you have an unseen global n), and you clearly meant to use the m value returned by the first vsnprintf call.

Also, a critical memory allocation mistake: vsnprintf returns the number of characters that would be written excluding the null terminator. So when allocating memory, you need m + 1 bytes (not n-1) to fit the full string plus the required null byte. Using m-1 would truncate your string, defeating the purpose of a "safe" snprintf.

Fixed SAFE_snprintf Implementation

Here's a corrected version using va_copy to handle variable arguments properly, plus fixes for the memory allocation and variable issues:

#define long_string 256
typedef char STRING_VARIABLE [long_string + 1];

void SAFE_snprintf(char *buffer, const char *format, ...) {
    va_list args, args_copy;
    va_start(args, format);
    va_copy(args_copy, args); // Make a copy of the original argument list

    // Calculate the required buffer length
    int m = vsnprintf(NULL, 0, format, args);
    va_end(args); // We're done with the original list for now

    printf("m = %d\n", m);
    if (m < 0) {
        perror("vsnprintf failed");
        abort();
    }

    // Allocate enough memory (plus 1 for the null terminator)
    char *bufferString = (char *)malloc(m + 1);
    if (!bufferString) {
        perror("malloc failed");
        abort();
    }

    // Use the copied list to do the actual formatting
    m = vsnprintf(bufferString, m + 1, format, args_copy);
    va_end(args_copy);

    if (m < 0) {
        perror("vsnprintf failed");
        free(bufferString); // Don't leak memory if formatting fails
        abort();
    }

    // Important: Add a check here if `buffer` has a fixed size!
    // Right now, if the formatted string is longer than long_string, strcpy will overflow
    strcpy(buffer, bufferString);
    free(bufferString);
}

int main(int argc, char *argv[]) {
    char InputString[] = "Hello";
    STRING_VARIABLE bufferStrings;
    const char format[] = "%s_test";
    
    int n = snprintf(NULL, 0, format, InputString);
    if (n < 0) {
        perror("snprintf failed");
        abort();
    }
    printf("n = %d\n", n);
    
    SAFE_snprintf(bufferStrings, format, InputString);
    printf("Formatted result: %s\n", bufferStrings); // Verify the output
    return 0;
}

Extra Tips for Safety

  • Mark your format string as const char * to enforce type safety (standard practice for functions accepting format strings).
  • Add a buffer size parameter to SAFE_snprintf and use strncpy instead of strcpy to prevent overflowing the input buffer. Right now, if your formatted string exceeds long_string, you'll get a buffer overflow.
  • Always clean up allocated memory (like bufferString) if an error occurs after allocation to avoid memory leaks.

内容的提问来源于stack exchange,提问作者Muhammed Mahmood

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 11:18:11