parent
7f0234e7d5
commit
17ee4093fa
|
@ -466,6 +466,9 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken,
|
||||||
const Token * closingParenthesis = tok->linkAt(1);
|
const Token * closingParenthesis = tok->linkAt(1);
|
||||||
for (const Token *innerTok = tok->tokAt(2); innerTok && innerTok != closingParenthesis; innerTok = innerTok->next()) {
|
for (const Token *innerTok = tok->tokAt(2); innerTok && innerTok != closingParenthesis; innerTok = innerTok->next()) {
|
||||||
// TODO: replace with checkTokenInsideExpression()
|
// TODO: replace with checkTokenInsideExpression()
|
||||||
|
const Token* const openingPar = isFunctionCall(innerTok);
|
||||||
|
if (!openingPar)
|
||||||
|
checkTokenInsideExpression(innerTok, varInfo);
|
||||||
|
|
||||||
if (!isLocalVarNoAutoDealloc(innerTok, mTokenizer->isCPP()))
|
if (!isLocalVarNoAutoDealloc(innerTok, mTokenizer->isCPP()))
|
||||||
continue;
|
continue;
|
||||||
|
@ -502,7 +505,6 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for function call
|
// check for function call
|
||||||
const Token * const openingPar = isFunctionCall(innerTok);
|
|
||||||
if (openingPar) {
|
if (openingPar) {
|
||||||
const Library::AllocFunc* allocFunc = mSettings->library.getDeallocFuncInfo(innerTok);
|
const Library::AllocFunc* allocFunc = mSettings->library.getDeallocFuncInfo(innerTok);
|
||||||
// innerTok is a function name
|
// innerTok is a function name
|
||||||
|
@ -805,7 +807,8 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken,
|
||||||
const Token * vtok = typeEndTok->tokAt(3);
|
const Token * vtok = typeEndTok->tokAt(3);
|
||||||
const VarInfo::AllocInfo allocation(af ? af->groupId : (arrayDelete ? NEW_ARRAY : NEW), VarInfo::OWNED, ftok);
|
const VarInfo::AllocInfo allocation(af ? af->groupId : (arrayDelete ? NEW_ARRAY : NEW), VarInfo::OWNED, ftok);
|
||||||
changeAllocStatus(varInfo, allocation, vtok, vtok);
|
changeAllocStatus(varInfo, allocation, vtok, vtok);
|
||||||
}
|
} else if (Token::Match(tok, "%var% ."))
|
||||||
|
checkTokenInsideExpression(tok, varInfo);
|
||||||
}
|
}
|
||||||
ret(endToken, varInfo, true);
|
ret(endToken, varInfo, true);
|
||||||
return true;
|
return true;
|
||||||
|
@ -930,8 +933,7 @@ void CheckLeakAutoVar::changeAllocStatus(VarInfo &varInfo, const VarInfo::AllocI
|
||||||
void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpeningPar, VarInfo &varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af)
|
void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpeningPar, VarInfo &varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af)
|
||||||
{
|
{
|
||||||
// Ignore function call?
|
// Ignore function call?
|
||||||
if (mSettings->library.isLeakIgnore(mSettings->library.getFunctionName(tokName)))
|
const bool isLeakIgnore = mSettings->library.isLeakIgnore(mSettings->library.getFunctionName(tokName));
|
||||||
return;
|
|
||||||
if (mSettings->library.getReallocFuncInfo(tokName))
|
if (mSettings->library.getReallocFuncInfo(tokName))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -990,6 +992,8 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin
|
||||||
varAlloc.allocTok = arg;
|
varAlloc.allocTok = arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (isLeakIgnore)
|
||||||
|
checkTokenInsideExpression(arg, varInfo);
|
||||||
else
|
else
|
||||||
changeAllocStatus(varInfo, dealloc.type == 0 ? allocation : dealloc, tokName, arg);
|
changeAllocStatus(varInfo, dealloc.type == 0 ? allocation : dealloc, tokName, arg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -859,7 +859,7 @@ void memleak_scandir(void)
|
||||||
which is allocated via malloc(3). If filter is NULL, all entries are
|
which is allocated via malloc(3). If filter is NULL, all entries are
|
||||||
selected.*/
|
selected.*/
|
||||||
|
|
||||||
// TODO: cppcheck-suppress memleak
|
// cppcheck-suppress memleak
|
||||||
}
|
}
|
||||||
|
|
||||||
void no_memleak_scandir(void)
|
void no_memleak_scandir(void)
|
||||||
|
|
|
@ -5202,6 +5202,16 @@ private:
|
||||||
" for (int i = 0; i < N; a[i++] = false);\n"
|
" for (int i = 0; i < N; a[i++] = false);\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n" // #8192
|
||||||
|
" for (int i = 0; i > 10; ++i) {}\n"
|
||||||
|
"}\n");
|
||||||
|
TODO_ASSERT_EQUALS("[test.cpp:2]: (style) Condition 'i>10' is always false\n", "", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" for (int i = 1000; i < 20; ++i) {}\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (style) Condition 'i<20' is always false\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void alwaysTrueTryCatch()
|
void alwaysTrueTryCatch()
|
||||||
|
|
|
@ -112,6 +112,7 @@ private:
|
||||||
TEST_CASE(deallocuse11); // #8302
|
TEST_CASE(deallocuse11); // #8302
|
||||||
TEST_CASE(deallocuse12);
|
TEST_CASE(deallocuse12);
|
||||||
TEST_CASE(deallocuse13);
|
TEST_CASE(deallocuse13);
|
||||||
|
TEST_CASE(deallocuse14);
|
||||||
|
|
||||||
TEST_CASE(doublefree1);
|
TEST_CASE(doublefree1);
|
||||||
TEST_CASE(doublefree2);
|
TEST_CASE(doublefree2);
|
||||||
|
@ -924,6 +925,25 @@ private:
|
||||||
errout.str());
|
errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void deallocuse14() {
|
||||||
|
check("struct S { void f(); };\n" // #10905
|
||||||
|
"void g() {\n"
|
||||||
|
" S* s = new S;\n"
|
||||||
|
" delete s;\n"
|
||||||
|
" s->f();\n"
|
||||||
|
"}\n", true);
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (error) Dereferencing 's' after it is deallocated / released\n",
|
||||||
|
errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" int *p = (int*)malloc(4);\n"
|
||||||
|
" free(p);\n"
|
||||||
|
" if (*p == 5) {}\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.c:4]: (error) Dereferencing 'p' after it is deallocated / released\n",
|
||||||
|
errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void doublefree1() { // #3895
|
void doublefree1() { // #3895
|
||||||
check("void f(char *p) {\n"
|
check("void f(char *p) {\n"
|
||||||
" if (x)\n"
|
" if (x)\n"
|
||||||
|
@ -2996,7 +3016,14 @@ private:
|
||||||
" free(p);\n"
|
" free(p);\n"
|
||||||
" strcpy(a, p);\n"
|
" strcpy(a, p);\n"
|
||||||
"}");
|
"}");
|
||||||
TODO_ASSERT_EQUALS("error (free,use)", "", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (error) Dereferencing 'p' after it is deallocated / released\n", errout.str());
|
||||||
|
|
||||||
|
check("void f(char *p, const char *q) {\n" // #11665
|
||||||
|
" free(p);\n"
|
||||||
|
" strcpy(p, q);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (error) Dereferencing 'p' after it is deallocated / released\n",
|
||||||
|
errout.str());
|
||||||
|
|
||||||
check("void f(char *p) {\n" // #3041 - assigning pointer when it's used
|
check("void f(char *p) {\n" // #3041 - assigning pointer when it's used
|
||||||
" free(p);\n"
|
" free(p);\n"
|
||||||
|
|
|
@ -6335,6 +6335,21 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:15] -> [test.cpp:17]: (warning) Uninitialized variable: pwd\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:15] -> [test.cpp:17]: (warning) Uninitialized variable: pwd\n", errout.str());
|
||||||
|
|
||||||
|
valueFlowUninit("size_t Read(unsigned char* buffer, size_t len);\n" // #11540
|
||||||
|
"void f() {\n"
|
||||||
|
" const int N = 100;\n"
|
||||||
|
" uint8_t data[N];\n"
|
||||||
|
" size_t data_size = 0;\n"
|
||||||
|
" for (int i = 0; i < 10; i++) {\n"
|
||||||
|
" if (!data_size)\n"
|
||||||
|
" data_size = Read(data, N);\n"
|
||||||
|
" if (!data_size)\n"
|
||||||
|
" return;\n"
|
||||||
|
" if (data[0] == 0x47) {}\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
// #12033
|
// #12033
|
||||||
valueFlowUninit("void g(const char*p);\n"
|
valueFlowUninit("void g(const char*p);\n"
|
||||||
"void f() {\n"
|
"void f() {\n"
|
||||||
|
|
Loading…
Reference in New Issue