我创建了一个具有可变参数模板方法的类。此方法调用printf
函数。将零参数传递给方法时,我会收到gcc的编译警告:
警告:格式不是字符串文字而没有格式参数[-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
标志的情况下删除警告吗?
答案 0 :(得分:12)
这是一个预期的警告,如果我们查看-Wformat-security的文档,它会说:
-Wformat安全 如果指定了-Wformat,还会警告使用表示可能存在安全问题的格式函数。目前,会警告调用printf和scanf函数,其中格式字符串不是字符串文字,并且没有格式参数,如printf(foo); 。如果格式字符串来自不受信任的输入并且包含“%n&#39;”,则这可能是安全漏洞。 (目前这是-Wformat-nonliteral警告的子集,但是将来警告可能会添加到-Wformat-nonliteral中未包含的-Wformat-security。) -Wformat = 2
因为c_str()
的结果不是字符串文字而没有传递参数的情况。
这种情况:
printf("null\n");
不会发出警告,因为"null\n"
是不可能从用户输入的字符串文字。
我们可以从%n format specifier program giving different outputs on different compilers. Why?中了解为什么这是一个潜在的安全问题。
如果你不想要所有的-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");
}