Skip to content

[clang] False positive clang-analyzer-core.DivideZero with loop over container #81734

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
chrchr-github opened this issue Feb 14, 2024 · 4 comments
Labels
clang:static analyzer false-positive Warning fires when it should not

Comments

@chrchr-github
Copy link

chrchr-github commented Feb 14, 2024

#include <vector>
int f(const std::vector<int>& v) {
    if (v.empty())
        return 0;
    int h = 0;
    for (auto it = v.begin(); it != v.end(); ++it) {
        h = std::max(h, *it);
    }

    int x = 512;
    if (h < x)
        h = h * (x / h + 1);
    return h;
}
<source>:12:20: warning: Division by zero [clang-analyzer-core.DivideZero]
   12 |         h = h * (x / h + 1);
      |                  ~~^~~
<source>:3:9: note: Assuming the condition is false]
    3 |     if (v.empty())
      |         ^~~~~~~~~
<source>:3:5: note: Taking false branch]
    3 |     if (v.empty())
      |     ^
<source>:5:5: note: 'h' initialized to 0
    5 |     int h = 0;
      |     ^~~~~
<source>:6:5: note: Loop condition is false. Execution continues on line 10
    6 |     for (auto it = v.begin(); it != v.end(); ++it) {
      |     ^
<source>:11:9: note: 'h' is < 'x'
   11 |     if (h < x)
      |         ^
<source>:11:5: note: Taking true branch
   11 |     if (h < x)
      |     ^
<source>:12:20: note: Division by zero
   12 |         h = h * (x / h + 1);
      |                  ~~^~~

There could be division by zero if the vector holds only numbers <= 0. However, the diagnostic seems to imply that the vector might be empty, which is impossible.
Edit: also happens with h = 1; instead of h = std::max(h, *it);.
https://godbolt.org/z/cbKh7axxd

@github-actions github-actions bot added the clang Clang issues not falling into any other category label Feb 14, 2024
@EugeneZelenko EugeneZelenko added clang:static analyzer false-positive Warning fires when it should not and removed clang Clang issues not falling into any other category labels Feb 14, 2024
@llvmbot
Copy link
Member

llvmbot commented Feb 14, 2024

@llvm/issue-subscribers-clang-static-analyzer

Author: None (chrchr-github)

~~~c++ #include <vector> int f(const std::vector<int>& v) { if (v.empty()) return 0; int h = 0; for (auto it = v.begin(); it != v.end(); ++it) { h = std::max(h, *it); }
int x = 512;
if (h &lt; x)
    h = h * (x / h + 1);
return h;

}

<source>:12:20: warning: Division by zero [clang-analyzer-core.DivideZero]
12 | h = h * (x / h + 1);
| ^
<source>:3:9: note: Assuming the condition is false]
3 | if (v.empty())
| ^~~~~~~~~
<source>:3:5: note: Taking false branch]
3 | if (v.empty())
| ^
<source>:5:5: note: 'h' initialized to 0
5 | int h = 0;
| ^~~~~
<source>:6:5: note: Loop condition is false. Execution continues on line 10
6 | for (auto it = v.begin(); it != v.end(); ++it) {
| ^
<source>:11:9: note: 'h' is < 'x'
11 | if (h < x)
| ^
<source>:11:5: note: Taking true branch
11 | if (h < x)
| ^
<source>:12:20: note: Division by zero
12 | h = h * (x / h + 1);
| ^

There could be division by zero if the vector holds only numbers &lt;= 0. However, the diagnostic seems to imply that the vector might be empty, which is impossible.
https://godbolt.org/z/cbKh7axxd
</details>

@mzyKi
Copy link
Contributor

mzyKi commented Feb 29, 2024

This is not a false positive about core.DivideZero.I think std::vector::empty() function related of this.I try to use this commandclang-tidy --allow-enabling-analyzer-alpha-checkers -checks=-*,clang-analyzer-core.DivideZero,clang-analyzer-alpha.cplusplus.IteratorModeling test.cpp -- -Xclang -analyzer-config -Xclang aggressive-binary-operation-simplification=trueand reproduce this.I guess we should fix the lack of empty() in IteratorModeling.

@NagyDonat
Copy link
Contributor

You're right that the false positive is produced because the analyzer doesn't recognize connection between v.empty() and v.begin() != v.end(). (There is no stable checker that does this explicitly; and the implementation of these methods is either not available or too optimized/obfuscated for the analyzer.)

In an ideal world a checker like IteratorModeling would handle this issue; but unfortunately the code of the iterator-related checkers is infamously complex and difficult to modify. We know that they're somewhat buggy (that's why they're in alpha state) and it would be good to fix them eventually, but there are "lower hanging fruits" in other areas, so there is no progress on them.

@steakhal
Copy link
Contributor

steakhal commented Mar 5, 2024

There is an easier option for this problem.
I've actually seen many instances of useful (and tiny) member functions not getting inlined for std::array (this was today for an other case I investigated downstream), but I've seen it happen for std::vector and std::span, std::string_view as well.

Anyways, there is an analyzer option called c++-container-inlining, which defaults to false, but if you set it, then CSA will not immediatelly reject inlining methods/functions from the standard library. I haven't looked in detail to the initial example, but setting this option would get rid of the div-by-zero FP. See https://godbolt.org/z/vo8MdMEf7

Downstream, we will definitely experiment with enabling this option, but one needs to be careful about checking if running times, memory footprint and the report changes improve / or are acceptable for the benefit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:static analyzer false-positive Warning fires when it should not
Projects
None yet
Development

No branches or pull requests

6 participants