当我尝试在Ubuntu上编译fprintf(stderr,Usage)
时出现此错误:
error: format not a string literal and no format arguments [-Werror=format-security
但是当我在其他成功编译的Linux发行版(RedHat,Fedora,SUSE)上编译它时。
有人有想法吗?
答案 0 :(得分:19)
您应该使用fputs(Usage, stderr);
如果您不进行格式化,则无需使用fprintf。如果您想使用fprintf,请使用fprintf(stderr, "%s", Usage);
Ubuntu上的default compiler flags包含-Wformat -Wformat-security
,这就是出现此错误的原因。
该标志用作防止引入安全相关错误的预防措施,想象一下 如果你以某种方式这样做会发生:
char *Usage = "Usage %s, [options] ... ";
...
fprintf(stderr, Usage);
这与以下相同
fprintf(stderr, "Usage %s, [options] ... ]");
这是错误的。
现在Usage
字符串包含格式说明符%s
,但是您没有向fprintf
提供该参数,导致未定义的行为,可能导致程序崩溃或允许它利用。如果传递给fprintf的字符串来自用户输入,则更相关。
但如果你这样做fprintf(stderr,"%s", "Usage %s, [options] ... ]");
没有这样的问题。 2. %s
不会被解释为格式说明符。
gcc可以对此发出警告,默认的Ubuntu编译器标志会使其成为编译器错误。
答案 1 :(得分:8)
使用fputs(Usage)
或fprintf(stderr, "%s", Usage)
。将消息字符串传递给printf
- 族函数的习惯是危险的,因为除非知道不包含格式说明符,否则字符串中的任何可能的格式说明符都将被解释并导致未定义的行为(因为它们没有对应于它们的参数),这几乎总会转化为安全漏洞。
答案 2 :(得分:-1)
仅将fprintf()
与两个参数一起使用是完全正确的。正如函数定义明确指出的那样,第二个参数之后的所有参数都是可选的。
当第二个参数不包含format子句时,此警告实际上变成了一个错误,该错误是由于BAD假设fprintf()
的第二个参数将总是 包含格式子句。这个假设没有什么是真的。这是一个有缺陷的决定,是一个错误,已在较新版本的GCC中修复,该错误实际上检查了第二个参数,以确保在需要时可以正确显示附加参数的数量和类型。
混合fputs()
和fprintf()
呼叫是在询问错误。另外,它只会使代码更难看。只要您还使用了最新且健全的GCC,在任何地方使用fprintf()
都会更加干净。
这个故事的寓意很简单:永远不要修改好代码以使不好的编译器满意。