vsprintf and vsnprintf [-Wformat-nonliteral] warni

2019-07-01 10:14发布

问题:

i have this chunk of code

static void err_doit(int errnoflag, int level, const char *fmt, va_list ap)
{
    int     errno_save;
    unsigned long n;
char    buf[MAXLINE];
    errno_save = errno;    
    #ifdef  HAVE_VSNPRINTF
vsnprintf(buf, sizeof(buf), fmt, ap);   /* this is safe */
    #else
vsprintf(buf ,fmt, ap);         /* this is not safe */
    #endif
n = strlen(buf);
if (errnoflag)
    snprintf(buf + n, sizeof(buf) - n, ": %s", strerror(errno_save));
strcat(buf, "\n");

if (daemon_proc) {
    syslog(level,"%s", buf);
} else {
    fflush(stdout);     
    fputs(buf, stderr);
    fflush(stderr);
}
return;
}

when i compile it (Clang 5.0.0 with -Weverything) i obtain those warnings:

Building C object lib/netutils/CMakeFiles/netutils.dir/error.c.o
/Users/User/Desktop/project.cmake/lib/netutils/error.c:98:16: warning: format string is        not a string literal [-Wformat-nonliteral]
    vsprintf(buf ,fmt, ap);                 /* this is not safe */
                  ^~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/secure/_stdio.h:66:57: note: expanded from
  macro 'vsprintf'__builtin___vsprintf_chk (str, 0, __darwin_obsz(str), format, ap)
                                                    ^

the same thing happens with this other function vsnprintf(buf, sizeof(buf), fmt, ap);

how can i fix this warning?

Thanks

回答1:

Apparently the solution is to tell Clang that your vsnprintf is called within a function that implements the behaviour of the printf family of functions by, well, calling vsnprintf. You do this with an attribute, as described here:

__attribute__((__format__ (__printf__, 3, 0)))
static void err_doit(int errnoflag, int level, const char *fmt, va_list ap)
{
    ...
}

This checks whether the format string is a literal on the calling function. As err_doit takes already a va_list, you should specify the format on the functions that call it, too. The second number, which is 0 here, should then be the argument index of the variadic argument, .... See also this discussion.

Function attributes are a non-standard extension of gcc, which is also implemented for Clang. If you want to keep the code compiler independent, you should wrap the attributes in a macro that hides it for compilers that don't know attributes.

(Disclaimer: I couldn't check this with Clang, but it works for gcc. Edit: fixed wrong argument index in example)