snprintf 引发的问题

snprintf 引发的问题

snprintf 是 C/C++ 程序中最常见的函数了,但是snprintf 在Windows和 Linux上的行为并不一致,对于跨平台的开发,有时会带来严重的缓冲区溢出问题。

本文提供了一个安全检查的版本,保证了 Windows和 Linux上的行为的一致性,任何情况下不会溢出。

建议用户使用 snprintf_chkd_exit 版本,任何错误导致退出程序 ! 这样避免对 snprintf_chkd 的返回值进行检查,保证了逻辑清晰和程序健壮。

 


/**
 * snprintf_chkd()
 *   A checked version of snprintf() for both GCC and MSVC
 *
 * see:
 *   
 *   https://linux.die.net/man/3/snprintf
 *
 *   The functions snprintf() and vsnprintf() do not write more than size bytes
 *    (including the terminating null byte ('\0')).
 *   If the output was truncated due to this limit then the return value is the
 *    number of characters (excluding the terminating null byte) which would have
 *    been written to the final string if enough space had been available.
 *   Thus, a return value of size or more means that the output was truncated.
 */
static int snprintf_chkd (char *outputbuf, size_t bufsize, const char *format, ...)
{
    int len;

    va_list args;
    va_start(args, format);
    len = vsnprintf(outputbuf, bufsize, format, args);
    va_end(args);

    if (len < 0) {
        len = 0;
        *outputbuf = '\0';
    } else if (len >= (int) bufsize) {
        /* output was truncated due to bufsize limit */
        len = (int) bufsize - 1;

        /* for MSVC */
        outputbuf[len] = '\0';
    }

    return len;
}


/**
 * snprintf_chkd_exit()
 *   A crashed on error version of snprintf.
 *    
 *    If exitcode not given (= 0), same as snprintf_safe()
 */
static int snprintf_chkd_exit (int exitcode, char *outputbuf, size_t bufsize, const char *format, ...)
{
    int len;

    va_list args;
    va_start(args, format);
    len = vsnprintf(outputbuf, bufsize, format, args);
    va_end(args);

    if (len < 0) {
        len = 0;
        *outputbuf = '\0';

        /* exit on error if exitcode given (not 0) */
        if (exitcode) {
            fprintf(stderr, "(%s:%d) fatal: output error is encountered.\n", __FILE__, __LINE__);
            exit(exitcode);
        }
    } else if (len >= (int) bufsize) {
        /* output was truncated due to bufsize limit */
        len = (int) bufsize - 1;

        /* for MSVC */
        outputbuf[len] = '\0';

        /* exit on error if exitcode given (not 0) */
        if (exitcode) {
            fprintf(stderr, "(%s:%d) fatal: output was truncated. (%s...)\n", __FILE__, __LINE__, outputbuf);
            exit(exitcode);
        }
    }

    return len;
}

 

你可能感兴趣的:(linux,c,windows)