Clang 静态分析器未被零除

Clang static analyzer misses division by zero

我正在试验 clang 静态分析器,我发现 下面的例子,它错过了一个可能被零除的例子:

    #include <stdio.h>
    
    int k = 300;
    
    char *parse_mailpath_spec (char *str)
    {
        char *s;
        int pass_next;
    
        for (s = str, pass_next = 0; s && *s; s++)
        {
            if (pass_next == 4)
            {
                int j = 0;
                k = 5 / j;
            }
            if (*s == '\')
            {
                pass_next++;
                continue;
            }
            if (*s == '?' || *s == '%')
            {
                return s;
            }
        }
        return ((char *)NULL);
    }
    
    int main(int argc, char **argv)
    {
        if (parse_mailpath_spec(argv[1])) return 0;
        else return -1;
    }

如果我将 if (pass_next == 4) 更改为 if (pass_next == 3) 然后分析器 找到错误,并报告被零除 。 我想我太天真了,以为分析器不会停止 除非它能证明程序是安全的(?)

问题好像是,"does Clang static analyzer attempt to prove the program is safe?"

答案是

为什么不呢?

Clang 静态分析 (SA) 是 static analyzer, not a verifier。这意味着它会尝试查找错误。当它找不到更多错误时,而不是当程序被证明是正确的时候。

为什么会漏掉这个错误?

我还没有证实这一点,但很可能是 Clang SA 的内部抽象状态 收敛 在探索包含错误的路径之前。这意味着它认为它已经在其程序状态近似值的范围内探索了循环的所有可能的不同行为。作为 undecidability of static program analysis 的结果,任何静态分析都必须进行近似,而这些近似会导致它遗漏错误。在这种情况下,显然 Clang SA 愿意探索循环的四次迭代而不是五次。

其他工具能找到吗?

是的。在评论中,Andrey 说 PVS-Studio 找到了它,我没有理由怀疑这个说法。我敢肯定这不是唯一可以的工具。

但要注意:这有利有弊。一些工具只是报告更多的结果,通常不仅包括更多,而且包括 更大比例 的误报。

理想的静态分析工具可以找到足够多的真实错误来证明使用它的成本(加上许可它的成本,如果是商业的话),同时报告足够少的误报,使人们不会失去信心并停止使用它.这是一个很难达到的平衡,通常会因为缺少一个错误而放弃一个工具是错误的。