Fix #11008 FP doubleFree with pointer in struct (#4294)

This commit is contained in:
chrchr-github 2022-07-19 20:41:08 +02:00 committed by GitHub
parent 30b20d17cb
commit c736fe8787
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 12 deletions

View File

@ -356,8 +356,11 @@ const Token * astIsVariableComparison(const Token *tok, const std::string &comp,
} }
while (ret && ret->str() == ".") while (ret && ret->str() == ".")
ret = ret->astOperand2(); ret = ret->astOperand2();
if (ret && ret->str() == "=" && ret->astOperand1() && ret->astOperand1()->varId()) const Token* varTok = ret ? ret->astOperand1() : nullptr;
ret = ret->astOperand1(); while (varTok && varTok->str() == ".")
varTok = varTok->astOperand2();
if (ret && ret->str() == "=" && varTok && varTok->varId())
ret = varTok;
else if (ret && ret->varId() == 0U) else if (ret && ret->varId() == 0U)
ret = nullptr; ret = nullptr;
if (vartok) if (vartok)

View File

@ -442,33 +442,36 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
continue; continue;
// Check assignments in the if-statement. Skip multiple assignments since we don't track those // Check assignments in the if-statement. Skip multiple assignments since we don't track those
if (Token::Match(innerTok, "%var% =") && innerTok->astParent() == innerTok->next() && const Token* const eqTok = innerTok->astParent();
!(innerTok->next()->astParent() && innerTok->next()->astParent()->isAssignmentOp())) { if (Token::Match(innerTok, ".| %var% =") && Token::simpleMatch(eqTok, "=") &&
!(eqTok->astParent() && eqTok->astParent()->isAssignmentOp())) {
// allocation? // allocation?
// right ast part (after `=` operator) // right ast part (after `=` operator)
const Token* tokRightAstOperand = innerTok->next()->astOperand2(); const Token* tokRightAstOperand = eqTok->astOperand2();
while (tokRightAstOperand && tokRightAstOperand->isCast()) while (tokRightAstOperand && tokRightAstOperand->isCast())
tokRightAstOperand = tokRightAstOperand->astOperand2() ? tokRightAstOperand->astOperand2() : tokRightAstOperand->astOperand1(); tokRightAstOperand = tokRightAstOperand->astOperand2() ? tokRightAstOperand->astOperand2() : tokRightAstOperand->astOperand1();
const Token* const allocTok = Token::simpleMatch(eqTok->astOperand2(), "(") ? eqTok->astOperand2()->astOperand1() : eqTok->astOperand2();
const Token* const ptrTok = innerTok->astOperand2() ? innerTok->astOperand2() : innerTok;
if (tokRightAstOperand && Token::Match(tokRightAstOperand->previous(), "%type% (")) { if (tokRightAstOperand && Token::Match(tokRightAstOperand->previous(), "%type% (")) {
const Library::AllocFunc* f = mSettings->library.getAllocFuncInfo(tokRightAstOperand->previous()); const Library::AllocFunc* f = mSettings->library.getAllocFuncInfo(tokRightAstOperand->previous());
if (f && f->arg == -1) { if (f && f->arg == -1) {
VarInfo::AllocInfo& varAlloc = alloctype[innerTok->varId()]; VarInfo::AllocInfo& varAlloc = alloctype[ptrTok->varId()];
varAlloc.type = f->groupId; varAlloc.type = f->groupId;
varAlloc.status = VarInfo::ALLOC; varAlloc.status = VarInfo::ALLOC;
varAlloc.allocTok = tokRightAstOperand->previous(); varAlloc.allocTok = tokRightAstOperand->previous();
} else { } else {
// Fixme: warn about leak // Fixme: warn about leak
alloctype.erase(innerTok->varId()); alloctype.erase(ptrTok->varId());
} }
changeAllocStatusIfRealloc(alloctype, innerTok->tokAt(2), varTok); changeAllocStatusIfRealloc(alloctype, allocTok, varTok);
} else if (mTokenizer->isCPP() && Token::Match(innerTok->tokAt(2), "new !!(")) { } else if (mTokenizer->isCPP() && Token::Match(allocTok, "new !!(")) {
const Token* tok2 = innerTok->tokAt(2)->astOperand1(); const Token* tok2 = allocTok->astOperand1();
const bool arrayNew = (tok2 && (tok2->str() == "[" || (tok2->str() == "(" && tok2->astOperand1() && tok2->astOperand1()->str() == "["))); const bool arrayNew = (tok2 && (tok2->str() == "[" || (tok2->str() == "(" && tok2->astOperand1() && tok2->astOperand1()->str() == "[")));
VarInfo::AllocInfo& varAlloc = alloctype[innerTok->varId()]; VarInfo::AllocInfo& varAlloc = alloctype[ptrTok->varId()];
varAlloc.type = arrayNew ? NEW_ARRAY : NEW; varAlloc.type = arrayNew ? NEW_ARRAY : NEW;
varAlloc.status = VarInfo::ALLOC; varAlloc.status = VarInfo::ALLOC;
varAlloc.allocTok = innerTok->tokAt(2); varAlloc.allocTok = allocTok;
} }
} }

View File

@ -127,6 +127,7 @@ private:
TEST_CASE(doublefree10); // #8706 TEST_CASE(doublefree10); // #8706
TEST_CASE(doublefree11); TEST_CASE(doublefree11);
TEST_CASE(doublefree12); // #10502 TEST_CASE(doublefree12); // #10502
TEST_CASE(doublefree13); // #11008
// exit // exit
TEST_CASE(exit1); TEST_CASE(exit1);
@ -1396,6 +1397,20 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void doublefree13() { // #11008
check("struct buf_t { void* ptr; };\n"
"void f() {\n"
" struct buf_t buf;\n"
" if ((buf.ptr = malloc(10)) == NULL)\n"
" return;\n"
" free(buf.ptr);\n"
" if ((buf.ptr = malloc(10)) == NULL)\n"
" return;\n"
" free(buf.ptr);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void exit1() { void exit1() {
check("void f() {\n" check("void f() {\n"
" char *p = malloc(10);\n" " char *p = malloc(10);\n"