Clang 5.0上的vsprintf和vsnprintf [-Wformat-nonliteral]警告

时间:2013-11-23 19:55:25

标签: c network-programming clang printf

我有这段代码

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;
}

当我编译它时(Clang 5.0.0 with -Weverything)我得到了那些警告:

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)
                                                    ^

同样的事情发生在另一个函数vsnprintf(buf,sizeof(buf),fmt,ap);

我该如何修复此警告?

由于

1 个答案:

答案 0 :(得分:9)

显然,解决方法是告诉Clang你的vsnprintf是在一个函数中调用的,它通过调用printf来实现vsnprintf函数族的行为。您可以使用属性as described here执行此操作:

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

检查格式字符串是否是调用函数的文字。由于err_doit已经占用va_list,因此您应该在调用它的函数上指定格式。第二个数字(此处为0)应该是可变参数...的参数索引。请参阅also this discussion

函数属性是gcc的非标准扩展,也是为Clang实现的。如果要保持代码编译器独立,则应将属性包装在宏中,以便为不知道属性的编译器隐藏它。

(免责声明:我无法用Clang检查这个,但它适用于gcc。编辑:在示例中修复了错误的参数索引)