Skip to content

Fix #15116 FP stlFindInsert (modifying existing element) - #8968

Open
chrchr-github wants to merge 5 commits into
cppcheck-opensource:mainfrom
chrchr-github:chr_15116
Open

chrchr-github wants to merge 5 commits into
cppcheck-opensource:mainfrom
chrchr-github:chr_15116

Conversation

@chrchr-github

Copy link
Copy Markdown
Collaborator

No description provided.

Comment thread lib/checkstl.cpp Fixed
Comment thread test/teststl.cpp
" m[1] = true;\n"
"}\n",
dinit(CheckOptions, $.inconclusive = true));
ASSERT_EQUALS("", errout_str()); // TODO: warn about duplicate search

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we removing the warning here? We should just update the warning message.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to add the logic necessary to generate a fitting error message in this case. The condition handling also needs tweaking, see https://trac.cppcheck.net/ticket/15146

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I update the logic for the error message in #8975.

@dmcppcheck dmcppcheck left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI review

The PR fixes #15116, but the new ==-only filter in isMapFind() also removes valid stlFindInsert warnings. When a count() result is compared with != or < and the condition really means "not present", the insertion is still unconditional and the warning is correct. Two inputs lose a true positive:

  • if (s.count(x) != 1) s.insert(x); on a std::set
  • if (m.count(x) < 1) m[x] = 1;

Both warn on base and are silent with the PR. The check should look at what the comparison means (key absent vs. key present), not only at the operator. I found no crashes. The removal of the warning in the added test was already raised by pfultz2, so I don't repeat it.

Testing

Builds and tests

  • Built cppcheck and testrunner in pr/, and cppcheck in base/. Both built.
  • ./testrunner TestStl: 122 tests, 0 failures.

Scratch test

scratch/t1.cpp:

#include <map>
#include <set>
void f3(std::map<int,int>& m, int x) {
    if (m.count(x) < 1) { m[x] = 1; }
}
void f9(std::set<int>& s, int x) {
    if (s.count(x) != 1) { s.insert(x); }
}
void f4(std::map<int,int>& m, int x) {
    if (m.count(x) != 0) { m[x] = 1; }   // the #15116 case
}
void f6(std::map<int,int>& m, int x) {
    if (m.count(x) == 0) { m[x] = 1; }
}

Command: cppcheck -q --enable=performance --inconclusive --std=c++17 t1.cpp

Function base PR
f3 stlFindInsert no warning (lost true positive)
f9 stlFindInsert no warning (lost true positive)
f4 stlFindInsert no warning (intended fix)
f6 stlFindInsert stlFindInsert

In f3 and f9 the condition means "key absent", so the search before the insert is redundant, just like in f6, which still warns.

I also tried if/else versions where both branches assign the same value (find != end, count != 0, count == 1). Base warned on them and the PR does not. That code is unusual, and the suggested try_emplace would not be equivalent there, so I don't count it as a regression.


Automated review of 99b5261 by Claude. The pull request was built and tested locally.

Comment thread lib/checkstl.cpp
return {};
if (!tok->astOperand2())
return {};
if (!Token::simpleMatch(tok->astParent(), "=="))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI review

Requiring == is too narrow for count(), because the operator alone does not say whether the condition means "key absent". if (s.count(x) != 1) s.insert(x); on a std::set, and if (m.count(x) < 1) m[x] = 1;, both mean "absent". Base reported stlFindInsert for both, and with this PR neither warns: lost true positives.

The fix should check the meaning of the comparison: absent means == 0, != 1 (for a set), < 1 or <= 0. It should not filter on == only. A test for one of these cases would help too.

@dmcppcheck

Copy link
Copy Markdown

Test results for commit 99b5261 (tools/test-my-pr.py, main compared to this PR):

Test: http://ec2-16-170-140-253.eu-north-1.compute.amazonaws.com/pr-8968/
packages: 100
Differing warnings: 0 (+0 -0)
Timing: -0.1% (http://ec2-16-170-140-253.eu-north-1.compute.amazonaws.com/pr-8968/2026-10-27_09-03-02-99b5261b552f_timing.html)

Posted automatically by the cppcheck PR test runner. +N: warnings only with this PR, -N: warnings only with main. The AI review is written by Claude and can be wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants