将零参数包传递给printf

10

我创建了一个类,其中有一个可变模板方法。该方法调用 printf 函数。当在该方法中传递零个参数时,我会收到 gcc 编译器的警告:

warning: format not a string literal and no format arguments [-Wformat-security]

以下是一个简化的类示例:

class printer{
    std::map<int,std::string> str;
  public:
    printer(){
      str[0] = "null\n";
      str[1] = "%4d\n";
      str[2] = "%4d %4d\n";
      str[3] = "%4d %4d\n%4d\n";
    }
    template<typename ...Args>
    void print(Args... args){
      printf(str[sizeof...(args)].c_str(),args...);
    }
};
当使用

标签时,意味着段落结束。它通常与

标签一起使用来定义一个段落。

printer p;
p.print(23);
p.print(345,23);
一切编译顺利,但在使用时出现问题。
printer p;
p.print();

我收到了编译警告

main.cpp: In instantiation of ‘void printer::print(Args ...) [with Args = {}]’:
main.cpp:23:11:   required from here
main.cpp:17:50: warning: format not a string literal and no format arguments [-Wformat-security]
       printf(str[sizeof...(args)].c_str(),args...);

当然,如果我只是调用

printf("null\n");

没有警告出现。

有人能解释一下这是为什么吗?

我能否在不禁用-Wformat-security标志的情况下消除警告?


我曾在这里提出过一个几乎相同的问题(https://dev59.com/EIjca4cB1Zd3GeqP3_E_)。我没有将其标记为重复,因为我不确定您是否愿意使用类似于我建议的解决方案中的宏。如果它有效,请将其标记为重复。 - Pradhan
C++现在有printf吗?你正在调用C的printf... - Antti Haapala -- Слава Україні
@AnttiHaapala 有 std::printf... :) - hyde
1个回答

12

如果我们查看 -Wformat-security 的文档,可以发现这是一个预期的警告:

-Wformat-security 如果指定了 -Wformat,则还会警告可能存在安全问题的格式函数使用。目前,它将警告传递给 printf 和 scanf 函数的调用,其中格式字符串不是字符串文字,并且没有格式参数,例如 printf(foo); 如果格式字符串来自不受信任的输入并包含 %n,则这可能是一个安全漏洞。(这目前是 -Wformat-nonliteral 警告的子集,但未来 -Wformat-security 可能会添加到 -Wformat-nonliteral 中未包括的警告。) -Wformat=2

就是在您不传递参数时出现,因为c_str() 的结果不是一个字符串字面量

该情况:

printf("null\n");

不会发出警告是因为"null\n"是一个字符串字面量,不可能从用户处输入。

从这个使用 %n 格式指定符的程序在不同编译器上产生不同输出的问题中,我们可以看出这是一个潜在的安全问题。为什么?

如果你不想开启全部的-Wformat-secrity,可以看到以下内容:

-Wformat包含在-Wall中。要更好地控制某些格式检查方面,请使用选项-Wformat-y2k、-Wno-format-extra-args、-Wno-format-zero-length、-Wformat-nonliteral、-Wformat-security和-Wformat=2,但它们不包含在-Wall中。

尽管这是一个较差的选择,如果-Wformat-secrity后来添加了更多选项,那么您需要不断更新。

另一个选择是像AndyG提到的那样进行重载:

void print(){
  std::printf("null\n");
}

重载OP的“print”函数,使其变成一个不带参数的“无操作”函数,这是一个好主意吗? - AndyG
我不理解的是:为什么只有零参数情况下会出现无文字警告,而在其他情况下却没有? - ztik
@ctheo请看我在这里的答案,了解为什么无参数情况是一个问题的示例。 - Shafik Yaghmour
@AndyG 是的,我本来就想加上那个的,只是不得不离开一下。 - Shafik Yaghmour
感谢@ShafikYaghmour。因此,可以通过-Wformat-nonliteral选项避免警告。现在的挑战是如何真正保护软件免受格式化攻击。也许我稍后会发布另一个问题。 - ztik
@ctheo,重载方法似乎是更好的方法,因为您不必调整警告标志。 - Shafik Yaghmour

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接