Skip to content

Commit a7f827d

Browse files
authored
fix #13960: False negative: no error when freeing struct member twice (regression) (danmar#7626)
1 parent 129055d commit a7f827d

File tree

2 files changed

+19
-6
lines changed

2 files changed

+19
-6
lines changed

lib/checkleakautovar.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -413,8 +413,6 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken,
413413
// assignment..
414414
if (const Token* const tokAssignOp = isInit ? varTok : isAssignment(varTok)) {
415415

416-
if (Token::simpleMatch(tokAssignOp->astOperand1(), "."))
417-
continue;
418416
// taking address of another variable..
419417
if (Token::Match(tokAssignOp, "= %var% +|;|?|%comp%")) {
420418
if (varTok->tokAt(2)->varId() != varTok->varId()) {
@@ -730,8 +728,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken,
730728
VarInfo::AllocInfo allocation(af ? af->groupId : 0, VarInfo::DEALLOC, ftok);
731729
if (allocation.type == 0)
732730
allocation.status = VarInfo::NOALLOC;
733-
if (Token::simpleMatch(ftok->astParent(), "(") && Token::simpleMatch(ftok->astParent()->astOperand2(), "."))
734-
continue;
731+
735732
functionCall(ftok, openingPar, varInfo, allocation, af);
736733

737734
tok = ftok->linkAt(1);
@@ -886,7 +883,7 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t
886883
while (rhs->isCast()) {
887884
rhs = rhs->astOperand2() ? rhs->astOperand2() : rhs->astOperand1();
888885
}
889-
if (rhs->varId() == tok->varId() && isAssignment) {
886+
if ((rhs->str() == "." || rhs->varId() == tok->varId()) && isAssignment) {
890887
// simple assignment
891888
varInfo.erase(tok->varId());
892889
} else if (rhs->astParent() && rhs->str() == "(" && !mSettings->library.returnValue(rhs->astOperand1()).empty()) {
@@ -1024,7 +1021,10 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin
10241021
arg = arg->astOperand2() ? arg->astOperand2() : arg->astOperand1();
10251022
const Token * const argTypeStartTok = arg;
10261023

1027-
while (Token::Match(arg, "%name% :: %name%"))
1024+
if (Token::simpleMatch(arg, "."))
1025+
arg = arg->next();
1026+
1027+
while (Token::Match(arg, "%name% .|:: %name%"))
10281028
arg = arg->tokAt(2);
10291029

10301030
if ((Token::Match(arg, "%var% [-,)] !!.") && !(arg->variable() && arg->variable()->isArray())) ||

test/testleakautovar.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ class TestLeakAutoVar : public TestFixture {
109109
TEST_CASE(doublefree16);
110110
TEST_CASE(doublefree17); // #8109: delete with comma operator
111111
TEST_CASE(doublefree18);
112+
TEST_CASE(doublefree19); // #13960
112113

113114
// exit
114115
TEST_CASE(exit1);
@@ -1814,6 +1815,18 @@ class TestLeakAutoVar : public TestFixture {
18141815
ASSERT_EQUALS("", errout_str());
18151816
}
18161817

1818+
void doublefree19() {
1819+
check("struct S {\n"
1820+
" void *x;\n"
1821+
"};\n"
1822+
"void f(struct S *p)\n"
1823+
"{\n"
1824+
" free(p->x);\n"
1825+
" free(p->x);\n"
1826+
"}\n");
1827+
ASSERT_EQUALS("[test.c:6:3] -> [test.c:7:3]: (error) Memory pointed to by 'x' is freed twice. [doubleFree]\n", errout_str());
1828+
}
1829+
18171830
void exit1() {
18181831
check("void f() {\n"
18191832
" char *p = malloc(10);\n"

0 commit comments

Comments
 (0)