我正在使用以下内容阅读文件:
std::ifstream is( file_name );
std::string s;
if( !is.good() ) {
std::cout << "error opening file: " << file_name << std::endl;
} else {
while( !is.eof() ) {
s.clear();
is >> s;
if (s.empty()) continue;
if (s.size() < 1 || s.size()>0x7FFFFFFF ) {
std::cout << "implausible data" << std::endl;
continue;
}
char *ss = new char[ s.size() + 1 ]; // COVERITY bails out
// do something with the data
delete[]ss;
}
}
当我使用静态代码分析工具coverity(免费版)分析上述代码时,标有 COVERITY的行 会引发错误:
Untrusted value as argument (TAINTED_SCALAR)
tainted_data: Passing tainted variable > s.size() + 1UL to a tainted sink.
据我所知,我不能相信从文件读取的任何数据,但我没有看到如何在此阶段验证数据。
我已经检查s.size()
在错误行上方的if
- 条款范围内是否合理(尽管相当大)。
为什么掩护会向我发出警告?
另外,我应该应用哪些其他输入验证策略?
答案 0 :(得分:2)
在以下部分
if (s.empty())
continue;
if (s.size() < 1 || s.size() > 0x7FFFFFFF)
{
std::cout << "implausible data" << std::endl;
continue;
}
char * ss = new char[s.size() + 1];
验证逻辑依赖于s.size()
每次调用时都返回相同值的重要事实。在这种情况下,我们(人类)知道这将是真的,静态代码分析器可能无法实现这一点。
作为一种解决方法,请尝试引入一个局部变量并使用该变量。
const std::size_t length = s.size();
if (!length)
continue;
if (length < 1 || length > 0x7FFFFFFF)
{
std::cout << "implausible data" << std::endl;
continue;
}
char * ss = new char[length + 1];
在这里,分析器很容易判断length
不会改变其值。
围绕静态分析仪工具的局限性进行此类编码是否值得讨论尚待辩论。 GNU Coding Standards阻止了它。
不要让程序变得丑陋只是为了安抚lint,clang和GCC等静态分析工具以及
-Wconversion
和-Wundef
等额外警告选项。这些工具可以帮助查找错误和不清楚的代码,但是它们也可以生成如此多的错误警报,这会损害可读性,从而使用不必要的强制转换,包装和其他复杂操作来消除它们。例如,请不要将强制转换插入void或仅仅为安抚lint checker而调用无操作函数。
就个人而言,只要代码的可读性不会受到太大影响,我就不会感到太糟糕。在极端情况下,添加一个注释来解释为什么事情按照完成的方式完成可能是一个好主意。