1

我正在使用以下内容读取文件:

    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 bails out的行会抛出错误:

 Untrusted value as argument (TAINTED_SCALAR)
   tainted_data: Passing tainted variable > s.size() + 1UL to a tainted sink.

我知道我不能信任从文件中读取的任何数据,但我看不到在这个阶段如何验证数据。我已经在错误行上方的- 子句中检查它s.size()是否在合理的(尽管相当大)范围内。if

那么,为什么 Coverity 会向我发出警告呢?

另外,我应该应用哪些其他输入验证策略?

4

1 回答 1

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 编码标准不鼓励它。

不要仅仅为了安抚静态分析工具(例如 lint、clang 和 GCC)而使程序变得丑陋,并带有额外的警告选项(例如-Wconversion-Wundef. 这些工具可以帮助发现错误和不清晰的代码,但它们也可以生成太多的错误警报,以至于通过不必要的强制转换、包装器和其他复杂情况来使它们保持沉默会损害可读性。例如,请不要仅仅为了安抚 lint 检查器而插入强制转换为 void 或调用无操作函数。

就个人而言,只要代码的可读性不会受到太大影响,我对此并不会感到太糟糕。在极端情况下,添加注释来解释为什么事情会以它们的方式完成可能是一个好主意。

于 2014-12-02T22:13:38.477 回答