Fix #7031 (improve error message for memory related warnings) (#2204)

Printout both the locations on double free errors, mismatching
alloc/dealloc and dealloc return error.
This commit is contained in:
Rikard Falkeborn 2019-09-22 21:50:02 +02:00 committed by Daniel Marjamäki
parent 28d13e7567
commit bb5ac32872
3 changed files with 73 additions and 57 deletions

View File

@ -133,10 +133,10 @@ void CheckLeakAutoVar::leakError(const Token *tok, const std::string &varname, i
checkmemleak.memleakError(tok, varname); checkmemleak.memleakError(tok, varname);
} }
void CheckLeakAutoVar::mismatchError(const Token *tok, const std::string &varname) void CheckLeakAutoVar::mismatchError(const Token *deallocTok, const Token *allocTok, const std::string &varname)
{ {
const CheckMemoryLeak c(mTokenizer, mErrorLogger, mSettings); const CheckMemoryLeak c(mTokenizer, mErrorLogger, mSettings);
const std::list<const Token *> callstack(1, tok); const std::list<const Token *> callstack = { allocTok, deallocTok };
c.mismatchAllocDealloc(callstack, varname); c.mismatchAllocDealloc(callstack, varname);
} }
@ -146,9 +146,10 @@ void CheckLeakAutoVar::deallocUseError(const Token *tok, const std::string &varn
c.deallocuseError(tok, varname); c.deallocuseError(tok, varname);
} }
void CheckLeakAutoVar::deallocReturnError(const Token *tok, const std::string &varname) void CheckLeakAutoVar::deallocReturnError(const Token *tok, const Token *deallocTok, const std::string &varname)
{ {
reportError(tok, Severity::error, "deallocret", "$symbol:" + varname + "\nReturning/dereferencing '$symbol' after it is deallocated / released", CWE672, false); const std::list<const Token *> locations = { deallocTok, tok };
reportError(locations, Severity::error, "deallocret", "$symbol:" + varname + "\nReturning/dereferencing '$symbol' after it is deallocated / released", CWE672, false);
} }
void CheckLeakAutoVar::configurationInfo(const Token* tok, const std::string &functionName) void CheckLeakAutoVar::configurationInfo(const Token* tok, const std::string &functionName)
@ -161,12 +162,14 @@ void CheckLeakAutoVar::configurationInfo(const Token* tok, const std::string &fu
} }
} }
void CheckLeakAutoVar::doubleFreeError(const Token *tok, const std::string &varname, int type) void CheckLeakAutoVar::doubleFreeError(const Token *tok, const Token *prevFreeTok, const std::string &varname, int type)
{ {
const std::list<const Token *> locations = { prevFreeTok, tok };
if (Library::isresource(type)) if (Library::isresource(type))
reportError(tok, Severity::error, "doubleFree", "$symbol:" + varname + "\nResource handle '$symbol' freed twice.", CWE415, false); reportError(locations, Severity::error, "doubleFree", "$symbol:" + varname + "\nResource handle '$symbol' freed twice.", CWE415, false);
else else
reportError(tok, Severity::error, "doubleFree", "$symbol:" + varname + "\nMemory pointed to by '$symbol' is freed twice.", CWE415, false); reportError(locations, Severity::error, "doubleFree", "$symbol:" + varname + "\nMemory pointed to by '$symbol' is freed twice.", CWE415, false);
} }
@ -381,6 +384,7 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
VarInfo::AllocInfo& varAlloc = alloctype[varTok->varId()]; VarInfo::AllocInfo& varAlloc = alloctype[varTok->varId()];
varAlloc.type = f->groupId; varAlloc.type = f->groupId;
varAlloc.status = VarInfo::ALLOC; varAlloc.status = VarInfo::ALLOC;
varAlloc.allocTok = fTok;
} }
changeAllocStatusIfRealloc(alloctype, fTok, varTok); changeAllocStatusIfRealloc(alloctype, fTok, varTok);
@ -390,6 +394,7 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
VarInfo::AllocInfo& varAlloc = alloctype[varTok->varId()]; VarInfo::AllocInfo& varAlloc = alloctype[varTok->varId()];
varAlloc.type = arrayNew ? NEW_ARRAY : NEW; varAlloc.type = arrayNew ? NEW_ARRAY : NEW;
varAlloc.status = VarInfo::ALLOC; varAlloc.status = VarInfo::ALLOC;
varAlloc.allocTok = varTok->tokAt(2);
} }
// Assigning non-zero value variable. It might be used to // Assigning non-zero value variable. It might be used to
@ -425,6 +430,7 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
VarInfo::AllocInfo& varAlloc = alloctype[innerTok->varId()]; VarInfo::AllocInfo& varAlloc = alloctype[innerTok->varId()];
varAlloc.type = f->groupId; varAlloc.type = f->groupId;
varAlloc.status = VarInfo::ALLOC; varAlloc.status = VarInfo::ALLOC;
varAlloc.allocTok = tokRightAstOperand->previous();
} else { } else {
// Fixme: warn about leak // Fixme: warn about leak
alloctype.erase(innerTok->varId()); alloctype.erase(innerTok->varId());
@ -437,6 +443,7 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
VarInfo::AllocInfo& varAlloc = alloctype[innerTok->varId()]; VarInfo::AllocInfo& varAlloc = alloctype[innerTok->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);
} }
} }
@ -598,6 +605,7 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
// delete // delete
else if (mTokenizer->isCPP() && tok->str() == "delete") { else if (mTokenizer->isCPP() && tok->str() == "delete") {
const Token * delTok = tok;
const bool arrayDelete = Token::simpleMatch(tok->next(), "[ ]"); const bool arrayDelete = Token::simpleMatch(tok->next(), "[ ]");
if (arrayDelete) if (arrayDelete)
tok = tok->tokAt(3); tok = tok->tokAt(3);
@ -609,7 +617,7 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
tok = tok->tokAt(2); tok = tok->tokAt(2);
const bool isnull = tok->hasKnownIntValue() && tok->values().front().intvalue == 0; const bool isnull = tok->hasKnownIntValue() && tok->values().front().intvalue == 0;
if (!isnull && tok->varId() && tok->strAt(1) != "[") { if (!isnull && tok->varId() && tok->strAt(1) != "[") {
const VarInfo::AllocInfo allocation(arrayDelete ? NEW_ARRAY : NEW, VarInfo::DEALLOC); const VarInfo::AllocInfo allocation(arrayDelete ? NEW_ARRAY : NEW, VarInfo::DEALLOC, delTok);
changeAllocStatus(varInfo, allocation, tok, tok); changeAllocStatus(varInfo, allocation, tok, tok);
} }
} }
@ -618,7 +626,7 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
else if (isFunctionCall(ftok)) { else if (isFunctionCall(ftok)) {
const Token * openingPar = isFunctionCall(ftok); const Token * openingPar = isFunctionCall(ftok);
const Library::AllocFunc* af = mSettings->library.getDeallocFuncInfo(ftok); const Library::AllocFunc* af = mSettings->library.getDeallocFuncInfo(ftok);
VarInfo::AllocInfo allocation(af ? af->groupId : 0, VarInfo::DEALLOC); VarInfo::AllocInfo allocation(af ? af->groupId : 0, VarInfo::DEALLOC, ftok);
if (allocation.type == 0) if (allocation.type == 0)
allocation.status = VarInfo::NOALLOC; allocation.status = VarInfo::NOALLOC;
functionCall(ftok, openingPar, varInfo, allocation, af); functionCall(ftok, openingPar, varInfo, allocation, af);
@ -716,7 +724,7 @@ void 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); const VarInfo::AllocInfo allocation(af ? af->groupId : (arrayDelete ? NEW_ARRAY : NEW), VarInfo::OWNED, ftok);
changeAllocStatus(varInfo, allocation, vtok, vtok); changeAllocStatus(varInfo, allocation, vtok, vtok);
} }
} }
@ -747,7 +755,7 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t
const Token * const openingPar = isFunctionCall(tok); const Token * const openingPar = isFunctionCall(tok);
if (openingPar) { if (openingPar) {
const Library::AllocFunc* allocFunc = mSettings->library.getDeallocFuncInfo(tok); const Library::AllocFunc* allocFunc = mSettings->library.getDeallocFuncInfo(tok);
VarInfo::AllocInfo alloc(allocFunc ? allocFunc->groupId : 0, VarInfo::DEALLOC); VarInfo::AllocInfo alloc(allocFunc ? allocFunc->groupId : 0, VarInfo::DEALLOC, tok);
if (alloc.type == 0) if (alloc.type == 0)
alloc.status = VarInfo::NOALLOC; alloc.status = VarInfo::NOALLOC;
functionCall(tok, openingPar, varInfo, alloc, nullptr); functionCall(tok, openingPar, varInfo, alloc, nullptr);
@ -766,10 +774,12 @@ void CheckLeakAutoVar::changeAllocStatusIfRealloc(std::map<int, VarInfo::AllocIn
VarInfo::AllocInfo& argAlloc = alloctype[argTok->varId()]; VarInfo::AllocInfo& argAlloc = alloctype[argTok->varId()];
VarInfo::AllocInfo& retAlloc = alloctype[retTok->varId()]; VarInfo::AllocInfo& retAlloc = alloctype[retTok->varId()];
if (argAlloc.type != 0 && argAlloc.type != f->groupId) if (argAlloc.type != 0 && argAlloc.type != f->groupId)
mismatchError(fTok, argTok->str()); mismatchError(fTok, argAlloc.allocTok, argTok->str());
argAlloc.status = VarInfo::DEALLOC; argAlloc.status = VarInfo::DEALLOC;
argAlloc.allocTok = fTok;
retAlloc.type = f->groupId; retAlloc.type = f->groupId;
retAlloc.status = VarInfo::ALLOC; retAlloc.status = VarInfo::ALLOC;
retAlloc.allocTok = fTok;
} }
} }
@ -785,18 +795,20 @@ void CheckLeakAutoVar::changeAllocStatus(VarInfo *varInfo, const VarInfo::AllocI
if (var->second.status == VarInfo::DEALLOC && arg->previous()->str() == "&") if (var->second.status == VarInfo::DEALLOC && arg->previous()->str() == "&")
varInfo->erase(arg->varId()); varInfo->erase(arg->varId());
} else if (var->second.managed()) { } else if (var->second.managed()) {
doubleFreeError(tok, arg->str(), allocation.type); doubleFreeError(tok, var->second.allocTok, arg->str(), allocation.type);
} else if (var->second.type != allocation.type) { } else if (var->second.type != allocation.type) {
// mismatching allocation and deallocation // mismatching allocation and deallocation
mismatchError(tok, arg->str()); mismatchError(tok, var->second.allocTok, arg->str());
varInfo->erase(arg->varId()); varInfo->erase(arg->varId());
} else { } else {
// deallocation // deallocation
var->second.status = allocation.status; var->second.status = allocation.status;
var->second.type = allocation.type; var->second.type = allocation.type;
var->second.allocTok = allocation.allocTok;
} }
} else if (allocation.status != VarInfo::NOALLOC) { } else if (allocation.status != VarInfo::NOALLOC) {
alloctype[arg->varId()].status = VarInfo::DEALLOC; alloctype[arg->varId()].status = VarInfo::DEALLOC;
alloctype[arg->varId()].allocTok = tok;
} }
} }
@ -844,6 +856,7 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin
// Check smart pointer // Check smart pointer
else if (Token::Match(arg, "%name% < %type%") && mSettings->library.isSmartPointer(argTypeStartTok)) { else if (Token::Match(arg, "%name% < %type%") && mSettings->library.isSmartPointer(argTypeStartTok)) {
const Token * typeEndTok = arg->linkAt(1); const Token * typeEndTok = arg->linkAt(1);
const Token * allocTok = nullptr;
if (!Token::Match(typeEndTok, "> {|( %var% ,|)|}")) if (!Token::Match(typeEndTok, "> {|( %var% ,|)|}"))
continue; continue;
@ -874,15 +887,17 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin
const Scope * tscope = dtok->type()->classScope; const Scope * tscope = dtok->type()->classScope;
for (const Token *tok2 = tscope->bodyStart; tok2 != tscope->bodyEnd; tok2 = tok2->next()) { for (const Token *tok2 = tscope->bodyStart; tok2 != tscope->bodyEnd; tok2 = tok2->next()) {
sp_af = mSettings->library.getDeallocFuncInfo(tok2); sp_af = mSettings->library.getDeallocFuncInfo(tok2);
if (sp_af) if (sp_af) {
allocTok = tok2;
break; break;
}
} }
} }
} }
} }
const Token * vtok = typeEndTok->tokAt(2); const Token * vtok = typeEndTok->tokAt(2);
const VarInfo::AllocInfo sp_allocation(sp_af ? sp_af->groupId : (arrayDelete ? NEW_ARRAY : NEW), VarInfo::OWNED); const VarInfo::AllocInfo sp_allocation(sp_af ? sp_af->groupId : (arrayDelete ? NEW_ARRAY : NEW), VarInfo::OWNED, allocTok);
changeAllocStatus(varInfo, sp_allocation, vtok, vtok); changeAllocStatus(varInfo, sp_allocation, vtok, vtok);
} else { } else {
checkTokenInsideExpression(arg, varInfo); checkTokenInsideExpression(arg, varInfo);
@ -955,7 +970,7 @@ void CheckLeakAutoVar::ret(const Token *tok, const VarInfo &varInfo)
// return deallocated pointer // return deallocated pointer
if (used && it->second.status == VarInfo::DEALLOC) if (used && it->second.status == VarInfo::DEALLOC)
deallocReturnError(tok, var->name()); deallocReturnError(tok, it->second.allocTok, var->name());
else if (!used && !it->second.managed()) { else if (!used && !it->second.managed()) {
const std::map<int, std::string>::const_iterator use = possibleUsage.find(varid); const std::map<int, std::string>::const_iterator use = possibleUsage.find(varid);

View File

@ -46,7 +46,8 @@ public:
* checkleakautovar allocation type. * checkleakautovar allocation type.
*/ */
int type; int type;
AllocInfo(int type_ = 0, AllocStatus status_ = NOALLOC) : status(status_), type(type_) {} const Token * allocTok;
AllocInfo(int type_ = 0, AllocStatus status_ = NOALLOC, const Token* allocTok_ = nullptr) : status(status_), type(type_), allocTok(allocTok_) {}
bool managed() const { bool managed() const {
return status < 0; return status < 0;
@ -142,19 +143,19 @@ private:
void leakIfAllocated(const Token *vartok, const VarInfo &varInfo); void leakIfAllocated(const Token *vartok, const VarInfo &varInfo);
void leakError(const Token* tok, const std::string &varname, int type); void leakError(const Token* tok, const std::string &varname, int type);
void mismatchError(const Token* tok, const std::string &varname); void mismatchError(const Token* deallocTok, const Token* allocTok, const std::string &varname);
void deallocUseError(const Token *tok, const std::string &varname); void deallocUseError(const Token *tok, const std::string &varname);
void deallocReturnError(const Token *tok, const std::string &varname); void deallocReturnError(const Token *tok, const Token *deallocTok, const std::string &varname);
void doubleFreeError(const Token *tok, const std::string &varname, int type); void doubleFreeError(const Token *tok, const Token *prevFreeTok, const std::string &varname, int type);
/** message: user configuration is needed to complete analysis */ /** message: user configuration is needed to complete analysis */
void configurationInfo(const Token* tok, const std::string &functionName); void configurationInfo(const Token* tok, const std::string &functionName);
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const OVERRIDE { void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const OVERRIDE {
CheckLeakAutoVar c(nullptr, settings, errorLogger); CheckLeakAutoVar c(nullptr, settings, errorLogger);
c.deallocReturnError(nullptr, "p"); c.deallocReturnError(nullptr, nullptr, "p");
c.configurationInfo(nullptr, "f"); // user configuration is needed to complete analysis c.configurationInfo(nullptr, "f"); // user configuration is needed to complete analysis
c.doubleFreeError(nullptr, "varname", 0); c.doubleFreeError(nullptr, nullptr, "varname", 0);
} }
static std::string myName() { static std::string myName() {

View File

@ -513,7 +513,7 @@ private:
" free(p);\n" " free(p);\n"
" return p;\n" " return p;\n"
"}"); "}");
ASSERT_EQUALS("[test.c:3]: (error) Returning/dereferencing 'p' after it is deallocated / released\n", errout.str()); ASSERT_EQUALS("[test.c:2] -> [test.c:3]: (error) Returning/dereferencing 'p' after it is deallocated / released\n", errout.str());
check("void f(char *p) {\n" check("void f(char *p) {\n"
" if (!p) free(p);\n" " if (!p) free(p);\n"
@ -621,14 +621,14 @@ private:
" p = 0;\n" " p = 0;\n"
" free(p);\n" " free(p);\n"
"}"); "}");
ASSERT_EQUALS("[test.c:6]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.c:3] -> [test.c:6]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str());
check( check(
"void foo(char *p) {\n" "void foo(char *p) {\n"
" free(p);\n" " free(p);\n"
" free(p);\n" " free(p);\n"
"}"); "}");
ASSERT_EQUALS("[test.c:3]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.c:2] -> [test.c:3]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str());
check( check(
"void foo(char *p, char *r) {\n" "void foo(char *p, char *r) {\n"
@ -665,7 +665,7 @@ private:
" bar();\n" " bar();\n"
" free(p);\n" " free(p);\n"
"}"); "}");
ASSERT_EQUALS("[test.c:4]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.c:2] -> [test.c:4]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str());
check( check(
"void foo(char *p) {\n" "void foo(char *p) {\n"
@ -673,14 +673,14 @@ private:
" printf(\"Freed memory at location %x\", p);\n" " printf(\"Freed memory at location %x\", p);\n"
" free(p);\n" " free(p);\n"
"}"); "}");
ASSERT_EQUALS("[test.c:4]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.c:2] -> [test.c:4]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str());
check( check(
"void foo(FILE *p) {\n" "void foo(FILE *p) {\n"
" fclose(p);\n" " fclose(p);\n"
" fclose(p);\n" " fclose(p);\n"
"}"); "}");
ASSERT_EQUALS("[test.c:3]: (error) Resource handle 'p' freed twice.\n", errout.str()); ASSERT_EQUALS("[test.c:2] -> [test.c:3]: (error) Resource handle 'p' freed twice.\n", errout.str());
check( check(
"void foo(FILE *p, FILE *r) {\n" "void foo(FILE *p, FILE *r) {\n"
@ -710,7 +710,7 @@ private:
" gethandle();\n" " gethandle();\n"
" fclose(p);\n" " fclose(p);\n"
"}"); "}");
ASSERT_EQUALS("[test.c:4]: (error) Resource handle 'p' freed twice.\n", errout.str()); ASSERT_EQUALS("[test.c:2] -> [test.c:4]: (error) Resource handle 'p' freed twice.\n", errout.str());
check( check(
"void foo(Data* p) {\n" "void foo(Data* p) {\n"
@ -739,7 +739,7 @@ private:
" }\n" " }\n"
" free(p);\n" " free(p);\n"
"}"); "}");
ASSERT_EQUALS("[test.c:7]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.c:4] -> [test.c:7]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str());
check( check(
"void f() {\n" "void f() {\n"
@ -755,7 +755,7 @@ private:
" delete p;\n" " delete p;\n"
" delete p;\n" " delete p;\n"
"}", true); "}", true);
ASSERT_EQUALS("[test.cpp:3]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str());
check( check(
"void foo(char *p, char *r) {\n" "void foo(char *p, char *r) {\n"
@ -792,14 +792,14 @@ private:
" bar();\n" " bar();\n"
" delete p;\n" " delete p;\n"
"}", true); "}", true);
ASSERT_EQUALS("[test.cpp:4]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:4]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str());
check( check(
"void foo(char *p) {\n" "void foo(char *p) {\n"
" delete[] p;\n" " delete[] p;\n"
" delete[] p;\n" " delete[] p;\n"
"}", true); "}", true);
ASSERT_EQUALS("[test.cpp:3]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str());
check( check(
"void foo(char *p, char *r) {\n" "void foo(char *p, char *r) {\n"
@ -822,7 +822,7 @@ private:
" bar();\n" " bar();\n"
" delete[] p;\n" " delete[] p;\n"
"}", true); "}", true);
ASSERT_EQUALS("[test.cpp:4]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:4]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str());
check( check(
"LineMarker::~LineMarker() {\n" "LineMarker::~LineMarker() {\n"
@ -866,7 +866,7 @@ private:
" delete a;\n" " delete a;\n"
" return 0;\n" " return 0;\n"
"}", true); "}", true);
TODO_ASSERT_EQUALS("", "[test.cpp:11]: (error) Memory pointed to by 'a' is freed twice.\n", errout.str()); TODO_ASSERT_EQUALS("", "[test.cpp:8] -> [test.cpp:11]: (error) Memory pointed to by 'a' is freed twice.\n", errout.str());
check( check(
"void foo(int y)\n" "void foo(int y)\n"
@ -956,7 +956,7 @@ private:
" }\n" " }\n"
" free(p);\n" " free(p);\n"
"}"); "}");
ASSERT_EQUALS("[test.c:8]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.c:6] -> [test.c:8]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str());
check( check(
"void MyFunction()\n" "void MyFunction()\n"
@ -1068,7 +1068,7 @@ private:
" x = (q == p);\n" " x = (q == p);\n"
" free(p);\n" " free(p);\n"
"}"); "}");
ASSERT_EQUALS("[test.c:4]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.c:2] -> [test.c:4]: (error) Memory pointed to by 'p' is freed twice.\n", errout.str());
} }
void doublefree6() { // #7685 void doublefree6() { // #7685
@ -1101,35 +1101,35 @@ private:
" std::unique_ptr<int> x(i);\n" " std::unique_ptr<int> x(i);\n"
" delete i;\n" " delete i;\n"
"}\n", true); "}\n", true);
ASSERT_EQUALS("[test.cpp:4]: (error) Memory pointed to by 'i' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (error) Memory pointed to by 'i' is freed twice.\n", errout.str());
check("void f() {\n" check("void f() {\n"
" int * i = new int;\n" " int * i = new int;\n"
" delete i;\n" " delete i;\n"
" std::unique_ptr<int> x(i);\n" " std::unique_ptr<int> x(i);\n"
"}\n", true); "}\n", true);
ASSERT_EQUALS("[test.cpp:4]: (error) Memory pointed to by 'i' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (error) Memory pointed to by 'i' is freed twice.\n", errout.str());
check("void f() {\n" check("void f() {\n"
" int * i = new int;\n" " int * i = new int;\n"
" std::unique_ptr<int> x{i};\n" " std::unique_ptr<int> x{i};\n"
" delete i;\n" " delete i;\n"
"}\n", true); "}\n", true);
ASSERT_EQUALS("[test.cpp:4]: (error) Memory pointed to by 'i' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (error) Memory pointed to by 'i' is freed twice.\n", errout.str());
check("void f() {\n" check("void f() {\n"
" int * i = new int;\n" " int * i = new int;\n"
" std::shared_ptr<int> x(i);\n" " std::shared_ptr<int> x(i);\n"
" delete i;\n" " delete i;\n"
"}\n", true); "}\n", true);
ASSERT_EQUALS("[test.cpp:4]: (error) Memory pointed to by 'i' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (error) Memory pointed to by 'i' is freed twice.\n", errout.str());
check("void f() {\n" check("void f() {\n"
" int * i = new int;\n" " int * i = new int;\n"
" std::shared_ptr<int> x{i};\n" " std::shared_ptr<int> x{i};\n"
" delete i;\n" " delete i;\n"
"}\n", true); "}\n", true);
ASSERT_EQUALS("[test.cpp:4]: (error) Memory pointed to by 'i' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (error) Memory pointed to by 'i' is freed twice.\n", errout.str());
// Check for use-after-free FP // Check for use-after-free FP
check("void f() {\n" check("void f() {\n"
@ -1144,7 +1144,7 @@ private:
" std::unique_ptr<int[]> x(i);\n" " std::unique_ptr<int[]> x(i);\n"
" delete i;\n" " delete i;\n"
"}\n", true); "}\n", true);
ASSERT_EQUALS("[test.cpp:4]: (error) Memory pointed to by 'i' is freed twice.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (error) Memory pointed to by 'i' is freed twice.\n", errout.str());
} }
void doublefree9() { void doublefree9() {
@ -1477,13 +1477,13 @@ private:
" FILE*f=fopen(fname,a);\n" " FILE*f=fopen(fname,a);\n"
" free(f);\n" " free(f);\n"
"}"); "}");
ASSERT_EQUALS("[test.c:3]: (error) Mismatching allocation and deallocation: f\n", errout.str()); ASSERT_EQUALS("[test.c:2] -> [test.c:3]: (error) Mismatching allocation and deallocation: f\n", errout.str());
check("void f() {\n" check("void f() {\n"
" FILE*f=fopen(fname,a);\n" " FILE*f=fopen(fname,a);\n"
" free((void*)f);\n" " free((void*)f);\n"
"}"); "}");
ASSERT_EQUALS("[test.c:3]: (error) Mismatching allocation and deallocation: f\n", errout.str()); ASSERT_EQUALS("[test.c:2] -> [test.c:3]: (error) Mismatching allocation and deallocation: f\n", errout.str());
check("void f() {\n" check("void f() {\n"
" char *cPtr = new char[100];\n" " char *cPtr = new char[100];\n"
@ -1493,13 +1493,13 @@ private:
" cPtr = new char[100];\n" " cPtr = new char[100];\n"
" delete cPtr;\n" " delete cPtr;\n"
"}", true); "}", true);
ASSERT_EQUALS("[test.cpp:7]: (error) Mismatching allocation and deallocation: cPtr\n", errout.str()); ASSERT_EQUALS("[test.cpp:6] -> [test.cpp:7]: (error) Mismatching allocation and deallocation: cPtr\n", errout.str());
check("void f() {\n" check("void f() {\n"
" char *cPtr = new char[100];\n" " char *cPtr = new char[100];\n"
" free(cPtr);\n" " free(cPtr);\n"
"}", true); "}", true);
ASSERT_EQUALS("[test.cpp:3]: (error) Mismatching allocation and deallocation: cPtr\n", errout.str()); ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (error) Mismatching allocation and deallocation: cPtr\n", errout.str());
check("void f() {\n" check("void f() {\n"
" char *cPtr = new (buf) char[100];\n" " char *cPtr = new (buf) char[100];\n"
@ -1510,21 +1510,21 @@ private:
" int * i = new int[1];\n" " int * i = new int[1];\n"
" std::unique_ptr<int> x(i);\n" " std::unique_ptr<int> x(i);\n"
"}\n", true); "}\n", true);
ASSERT_EQUALS("[test.cpp:3]: (error) Mismatching allocation and deallocation: i\n", errout.str()); ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (error) Mismatching allocation and deallocation: i\n", errout.str());
check("void f() {\n" check("void f() {\n"
" int * i = new int;\n" " int * i = new int;\n"
" std::unique_ptr<int[]> x(i);\n" " std::unique_ptr<int[]> x(i);\n"
"}\n", true); "}\n", true);
ASSERT_EQUALS("[test.cpp:3]: (error) Mismatching allocation and deallocation: i\n", errout.str()); ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (error) Mismatching allocation and deallocation: i\n", errout.str());
check("void f() {\n" check("void f() {\n"
" void* a = malloc(1);\n" " void* a = malloc(1);\n"
" void* b = freopen(f, p, a);\n" " void* b = freopen(f, p, a);\n"
" free(b);\n" " free(b);\n"
"}"); "}");
ASSERT_EQUALS("[test.c:3]: (error) Mismatching allocation and deallocation: a\n" ASSERT_EQUALS("[test.c:2] -> [test.c:3]: (error) Mismatching allocation and deallocation: a\n"
"[test.c:4]: (error) Mismatching allocation and deallocation: b\n", errout.str()); "[test.c:3] -> [test.c:4]: (error) Mismatching allocation and deallocation: b\n", errout.str());
check("void f() {\n" check("void f() {\n"
" void* a;\n" " void* a;\n"
@ -1538,8 +1538,8 @@ private:
" int * j = realloc(i, 2 * sizeof(int));\n" " int * j = realloc(i, 2 * sizeof(int));\n"
" delete[] j;\n" " delete[] j;\n"
"}", true); "}", true);
ASSERT_EQUALS("[test.cpp:3]: (error) Mismatching allocation and deallocation: i\n" ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (error) Mismatching allocation and deallocation: i\n"
"[test.cpp:4]: (error) Mismatching allocation and deallocation: j\n", errout.str()); "[test.cpp:3] -> [test.cpp:4]: (error) Mismatching allocation and deallocation: j\n", errout.str());
} }
void smartPointerDeleter() { void smartPointerDeleter() {
@ -1547,7 +1547,7 @@ private:
" FILE*f=fopen(fname,a);\n" " FILE*f=fopen(fname,a);\n"
" std::unique_ptr<FILE> fp{f};\n" " std::unique_ptr<FILE> fp{f};\n"
"}", true); "}", true);
ASSERT_EQUALS("[test.cpp:3]: (error) Mismatching allocation and deallocation: f\n", errout.str()); ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (error) Mismatching allocation and deallocation: f\n", errout.str());
check("void f() {\n" check("void f() {\n"
" FILE*f=fopen(fname,a);\n" " FILE*f=fopen(fname,a);\n"
@ -1600,13 +1600,13 @@ private:
" FILE*f=fopen(fname,a);\n" " FILE*f=fopen(fname,a);\n"
" std::shared_ptr<FILE> fp{f, [](FILE* x) { free(f); }};\n" " std::shared_ptr<FILE> fp{f, [](FILE* x) { free(f); }};\n"
"}", true); "}", true);
ASSERT_EQUALS("[test.cpp:3]: (error) Mismatching allocation and deallocation: f\n", errout.str()); ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (error) Mismatching allocation and deallocation: f\n", errout.str());
check("void f() {\n" check("void f() {\n"
" FILE*f=fopen(fname,a);\n" " FILE*f=fopen(fname,a);\n"
" std::shared_ptr<FILE> fp{f, [](FILE* x) {}};\n" " std::shared_ptr<FILE> fp{f, [](FILE* x) {}};\n"
"}", true); "}", true);
ASSERT_EQUALS("[test.cpp:3]: (error) Mismatching allocation and deallocation: f\n", errout.str()); ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (error) Mismatching allocation and deallocation: f\n", errout.str());
check("class C;\n" check("class C;\n"
"void f() {\n" "void f() {\n"