From 7bf6b359b150748303f2e4517f087bd4e512553b Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 27 Mar 2023 17:54:19 +0200 Subject: [PATCH] Fix #11616 false negative: functionConst (#4887) --- lib/checkclass.cpp | 2 +- lib/checkleakautovar.cpp | 8 ++++---- lib/checkleakautovar.h | 8 ++++---- lib/symboldatabase.h | 2 +- test/testclass.cpp | 23 ++++++++++++++++++++++- 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 9c93ffe9b..ea274dc5f 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -2328,7 +2328,7 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool& tok = tok->link(); else if ((tok->isName() && isMemberVar(scope, tok)) || (tok->isUnaryOp("&") && (tok = tok->astOperand1()) && isMemberVar(scope, tok))) { const Variable* var = tok->variable(); - if ((!var || !var->isMutable()) && mayModifyArgs) + if ((!var || (!var->isMutable() && !var->isConst())) && mayModifyArgs) return false; // TODO: Only bailout if function takes argument as non-const reference } } diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index b93f59408..0fe3daf8c 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -141,7 +141,7 @@ void VarInfo::possibleUsageAll(const std::string &functionName) } -void CheckLeakAutoVar::leakError(const Token *tok, const std::string &varname, int type) +void CheckLeakAutoVar::leakError(const Token *tok, const std::string &varname, int type) const { const CheckMemoryLeak checkmemleak(mTokenizer, mErrorLogger, mSettings); if (Library::isresource(type)) @@ -150,14 +150,14 @@ void CheckLeakAutoVar::leakError(const Token *tok, const std::string &varname, i checkmemleak.memleakError(tok, varname); } -void CheckLeakAutoVar::mismatchError(const Token *deallocTok, const Token *allocTok, const std::string &varname) +void CheckLeakAutoVar::mismatchError(const Token *deallocTok, const Token *allocTok, const std::string &varname) const { const CheckMemoryLeak c(mTokenizer, mErrorLogger, mSettings); const std::list callstack = { allocTok, deallocTok }; c.mismatchAllocDealloc(callstack, varname); } -void CheckLeakAutoVar::deallocUseError(const Token *tok, const std::string &varname) +void CheckLeakAutoVar::deallocUseError(const Token *tok, const std::string &varname) const { const CheckMemoryLeak c(mTokenizer, mErrorLogger, mSettings); c.deallocuseError(tok, varname); @@ -842,7 +842,7 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t } -void CheckLeakAutoVar::changeAllocStatusIfRealloc(std::map &alloctype, const Token *fTok, const Token *retTok) +void CheckLeakAutoVar::changeAllocStatusIfRealloc(std::map &alloctype, const Token *fTok, const Token *retTok) const { const Library::AllocFunc* f = mSettings->library.getReallocFuncInfo(fTok); if (f && f->arg == -1 && f->reallocArg > 0 && f->reallocArg <= numberOfArguments(fTok)) { diff --git a/lib/checkleakautovar.h b/lib/checkleakautovar.h index 882cd8594..217e6a331 100644 --- a/lib/checkleakautovar.h +++ b/lib/checkleakautovar.h @@ -144,7 +144,7 @@ private: void changeAllocStatus(VarInfo &varInfo, const VarInfo::AllocInfo& allocation, const Token* tok, const Token* arg); /** update allocation status if reallocation function */ - void changeAllocStatusIfRealloc(std::map &alloctype, const Token *fTok, const Token *retTok); + void changeAllocStatusIfRealloc(std::map &alloctype, const Token *fTok, const Token *retTok) const; /** return. either "return" or end of variable scope is seen */ void ret(const Token *tok, VarInfo &varInfo, const bool isEndOfScope = false); @@ -152,9 +152,9 @@ private: /** if variable is allocated then there is a leak */ void leakIfAllocated(const Token *vartok, const VarInfo &varInfo); - void leakError(const Token* tok, const std::string &varname, int type); - void mismatchError(const Token* deallocTok, const Token* allocTok, const std::string &varname); - void deallocUseError(const Token *tok, const std::string &varname); + void leakError(const Token* tok, const std::string &varname, int type) const; + void mismatchError(const Token* deallocTok, const Token* allocTok, const std::string &varname) const; + void deallocUseError(const Token *tok, const std::string &varname) const; void deallocReturnError(const Token *tok, const Token *deallocTok, const std::string &varname); void doubleFreeError(const Token *tok, const Token *prevFreeTok, const std::string &varname, int type); diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 707520971..3fd2bd448 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1454,7 +1454,7 @@ public: nonneg int sizeOfType(const Token *type) const; /** Set array dimensions when valueflow analysis is completed */ - void setArrayDimensionsUsingValueFlow(); + void setArrayDimensionsUsingValueFlow(); // cppcheck-suppress functionConst // has side effects void clangSetVariables(const std::vector &variableList); void createSymbolDatabaseExprIds(); diff --git a/test/testclass.cpp b/test/testclass.cpp index 2c3935d3f..76d079c92 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -198,6 +198,7 @@ private: TEST_CASE(const82); // ticket #11513 TEST_CASE(const83); TEST_CASE(const84); + TEST_CASE(const85); TEST_CASE(const_handleDefaultParameters); TEST_CASE(const_passThisToMemberOfOtherClass); @@ -6361,7 +6362,27 @@ private: ASSERT_EQUALS("", errout.str()); } - void const84() { // #11618 + void const84() { + checkConst("class S {};\n" // #11616 + "struct T {\n" + " T(const S*);\n" + " T(const S&);\n" + "};\n" + "struct C {\n" + " const S s;\n" + " void f1() {\n" + " T t(&s);\n" + " }\n" + " void f2() {\n" + " T t(s);\n" + " }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:8]: (style, inconclusive) Technically the member function 'C::f1' can be const.\n" + "[test.cpp:11]: (style, inconclusive) Technically the member function 'C::f2' can be const.\n", + errout.str()); + } + + void const85() { // #11618 checkConst("struct S {\n" " int a[2], b[2];\n" " void f() { f(a, b); }\n"