Clang static analyzer makes wrong assumptions whether a loop body is entered, even with sufficient context

Clang static analyzer gives the waring “warning: Division by zero [clang-analyzer-core.DivideZero]” on following code:

#include <vector>

unsigned func2(int x) {
    std::vector<int> v{x};
    unsigned count = 0;
    for (auto &y: v) {
        count++;
    }
    return 100 / count;
}

However, it fails to give any waring on the following code:

unsigned func2(int x) {
    std::vector<int> v;
    return 100 / v.size();
}

I am not clear with what strategy static analyzer takes to report warnings, but it seems not appropriate here.
BTW, is there any options to let clang not report warnings which lack sufficient evidience?

Yeah this keeps coming up, let me turn this into a github issue / canned response: [Umbrella] Overly eager assumption chains - the "if(x) if(y)" problem. · Issue #61669 · llvm/llvm-project · GitHub

Basically that’s the default behavior, that’s why there’s no warning in the second case, but due to our old choice of the fundamental technique behind the analyzer, we have to detect this after the fact and we do that imperfectly :frowning:

It works out pretty well on a lot of real-world code but it’s very easy to build simple examples on which it fails in embarrassing ways, and it can totally happen that your specific project is disproportionally affected by similar failures in these heuristics.

So if you run into a lot of these, you might want to disable these checks.

Normally the strategy is fully expressed by “path notes” attached to the warning. Basically every time you see a

note: Assuming ...

this means that the analyzer doesn’t have enough information to conclude that a certain branch is taken, so it has to consider both possibilities. Looks like there’s a separate bug with that: Compiler Explorer - it displays the “Assuming…” note correctly in the raw loop case but not in your range-based for-loop case :frowning: