13

当我尝试fprintf(stderr,Usage)在 Ubuntu 上编译时出现此错误:

 error: format not a string literal and no format arguments [-Werror=format-security

但是当我在成功编译的其他 Linux 发行版(RedHat、Fedora、SUSE)上编译它时。

有人有想法吗?

4

3 回答 3

24

你应该使用fputs(Usage, stderr);

如果您不进行格式化,则无需使用 fprintf。如果要使用 fprintf,请使用fprintf(stderr, "%s", Usage);

Ubuntu 上的默认编译器标志-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 编译器标志使其成为编译器错误。

于 2013-06-23T12:48:07.820 回答
8

使用fputs(Usage)fprintf(stderr, "%s", Usage)。将消息字符串传递给printf-family 函数的习惯用法很危险,因为除非已知它不包含格式说明符,否则字符串中任何可能的格式说明符都将被解释并导致未定义的行为(因为它们没有对应的参数) ,这几乎总是会转化为安全漏洞。

于 2013-06-23T12:49:17.477 回答
-1

fprintf()仅使用两个参数是完全正确的。正如函数定义清楚地表明的那样,第二个之后的所有参数都是可选的。

当第二个参数不包含格式子句时,这个警告实际上变成了一个错误,由于错误的假设第二个参数总是包含格式子句fprintf()而被引入 GCC。这个假设没有什么是真的。这是一个有缺陷的决定,一个错误,在较新版本的 GCC 中得到了修复,它实际上检查了第二个参数,以确保在需要时存在正确数量和类型的附加参数。

混合fputs()fprintf()调用是在要求错误。此外,它只会让代码更丑陋。fprintf()只要您还使用最新且健全的 GCC,它在任何地方都可以更清洁。

这个故事的寓意很简单:永远不要为了让糟糕的编译器高兴而修改好的代码。

于 2018-10-17T15:20:58.987 回答