Skip to content

Fix #15155 FN accessMoved (string concatenation using +=) - #8996

Open
chrchr-github wants to merge 3 commits into
cppcheck-opensource:mainfrom
chrchr-github:chr_15155
Open

chrchr-github wants to merge 3 commits into
cppcheck-opensource:mainfrom
chrchr-github:chr_15155

Conversation

@chrchr-github

Copy link
Copy Markdown
Collaborator

No description provided.

@dmcppcheck dmcppcheck left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review

The str().size() == 2 check that detects compound assignment leaves out <<= and >>=, because those operators are 3 characters long. So x <<= 1 / x >>= 1 on a moved object still gets no accessMoved warning, while x += 1 now does. The same gap makes other value types inconsistent: for example, int x; x += y; now gets an uninitvar warning, but int x; x <<= y; stays on legacyUninitvar. Writing it as tok->astParent()->str() != "=" (or Token::Match(parent, "%assign%") && parent->str() != "=") would cover every compound operator.

I found no other new problems. The full testrunner passes. The new nullPointerArithmetic on p += a with a default argument p = 0 matches what base already reports for p + a, so that change makes the two consistent rather than adding a new kind of false positive.

Testing

Built cppcheck and testrunner in pr/, and cppcheck in base/.

  • ./testrunner -q (all tests): 5387 tests, 0 failures.

<<= / >>= are missed (scratch/sh.cpp):

#include <utility>
#include <vector>
struct S { std::vector<int> v; S& operator+=(int); S& operator<<=(int); S& operator>>=(int); };
void s1(S x) { S a{ std::move(x) }; x += 1; }
void s2(S x) { S a{ std::move(x) }; x <<= 1; }
void s3(S x) { S a{ std::move(x) }; x >>= 1; }

cppcheck -q --enable=warning --library=std sh.cpp

  • base: nothing
  • pr: only sh.cpp:4:37: warning: Access of moved variable 'x'. [accessMoved]. Nothing is reported for lines 5 and 6.

The same inconsistency shows with uninitialized values: in pr, int x; x += y; gives uninitvar, but int x; x <<= y; still gives only legacyUninitvar.

Other checks:

  • The PR's case (std::string with += after a move) now gives accessMoved, as intended.
  • x = "abc"; x += "d"; and x.clear(); x += "d"; after a move: no false positive.
  • void f(int a, int *p = 0) { p += a; }: the new nullPointerArithmetic matches what base already reports for int *q = p + a;.
  • Integer x = 0; x += h(y); if (x == 0) and x |= h(y): no new warnings.

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

Comment thread lib/vf_analyzers.cpp
if (isVariableChanged(tok, getIndirect(tok), getSettings())) {
if (Token::Match(tok->astParent(), "*|[|.|++|--"))
if (Token::Match(tok->astParent(), "*|[|.|++|--") ||
(tok->astParent() && tok->astParent()->isAssignmentOp() && tok->astParent()->str().size() == 2)) // compound assignment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review

str().size() == 2 misses <<= and >>= (both 3 characters). For a moved S x with S& operator<<=(int), x <<= 1; still gets no accessMoved, while x += 1; now does. With uninitialized ints, x += y now gives uninitvar but x <<= y stays legacyUninitvar. tok->astParent()->str() != "=" would cover all compound assignments.

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.

2 participants