62 if (tok2 && tok2->
str() ==
"(") {
64 tok2 = tok2 ? tok2->
next() :
nullptr;
68 if (tok2->
str() ==
"::")
76 if (reallocType !=
No)
79 if (tok2->
isCpp() && tok2->
str() ==
"new") {
86 typeTok = typeTok->
tokAt(2);
87 const Scope* classScope =
nullptr;
88 if (typeTok->
type() && typeTok->
type()->isClassType()) {
89 classScope = typeTok->
type()->classScope;
91 classScope = typeTok->
function()->nestedIn;
99 if (
Token::Match(tok2,
"open|openat|creat|mkstemp|mkostemp|socket (")) {
103 if (tok2->
str() ==
"open" && num != 2 && num != 3)
128 tok2 = tok2->
tokAt(2);
136 if (callstack && std::find(callstack->cbegin(), callstack->cend(), func) != callstack->cend())
139 std::list<const Function*> cs;
143 callstack->push_back(func);
152 if (tok2 && tok2->
str() ==
"(") {
154 tok2 = tok2 ? tok2->
next() :
nullptr;
169 while (arg && arg->
isCast())
173 if (varid > 0 && !
Token::Match(arg,
"%varid% [,)]", varid))
177 if (realloctype > 0) {
195 if (vartok && vartok->
varId() == varid) {
196 if (tok->
strAt(1) ==
"[")
202 if (tok->
str() ==
"::")
211 const Token* vartok = tok2;
213 vartok = vartok->
tokAt(2);
220 if (tok->
str() ==
"close")
222 if (tok->
str() ==
"pclose")
228 if (dealloctype > 0) {
285 std::list<const Token *> callstack;
288 callstack.push_back(tok);
290 reportErr(callstack, severity,
id, msg, cwe);
309 reportErr(tok,
Severity::error,
"memleakOnRealloc",
"$symbol:" + varname +
"\nCommon " + reallocfunction +
" mistake: \'$symbol\' nulled but not freed upon failure",
CWE(401U));
314 std::string errmsg(
"Resource leak");
315 if (!varname.empty())
316 errmsg =
"$symbol:" + varname +
'\n' + errmsg +
": $symbol";
322 reportErr(tok,
Severity::error,
"deallocuse",
"$symbol:" + varname +
"\nDereferencing '$symbol' after it is deallocated / released",
CWE(416U));
327 reportErr(callstack,
Severity::error,
"mismatchAllocDealloc",
"$symbol:" + varname +
"\nMismatching allocation and deallocation: $symbol",
CWE(762U));
340 if (tok2->str() ==
"{" && !tok2->scope()->isExecutable())
342 if (tok2->str() ==
"return") {
347 if (tok2->scope() != func->
functionScope || !tok2->astOperand1())
378 if (!tok->isC() &&
Token::Match(tok,
"[(,] %varid% [,)]", varid)) {
387 if (allocType ==
No && tok->str() ==
"return")
404 return vartok && (vartok->
varId() == varid);
407 static bool ifvar(
const Token *tok,
nonneg int varid,
const std::string &comp,
const std::string &rhs)
414 if (!condition || condition->
str() ==
"&&")
418 return (vartok && vartok->
varId() == varid);
430 logChecker(
"CheckMemoryLeakInFunction::checkReallocUsage");
438 if (tok->varId() > 0 &&
Token::Match(tok,
"%name% =")) {
442 while (parTok && parTok->
isCast())
458 while (arg && arg->
isCast())
460 const Token* tok2 = tok;
469 if (!(tok->varId() == arg->
varId() && tok->variable() && !tok->variable()->isArgument()))
482 const Token* tokEndRealloc = reallocTok->
linkAt(1);
531 const std::string& varname = tokVarname->
str();
532 const int varid = tokVarname->
varId();
533 const std::string& classname = scope->
className;
539 bool allocInConstructor =
false;
540 bool deallocInDestructor =
false;
548 deallocInDestructor =
true;
568 if (tok->strAt(-1) ==
"=")
573 if (tok->strAt(-1) ==
"::" &&
577 const Token* allocTok = tok->
tokAt(body ? 2 : 3);
578 if (tok->astParent() && tok->astParent()->str() ==
"[" && tok->astParent()->astParent())
579 allocTok = tok->
astParent()->astParent()->astOperand2();
584 allocInConstructor =
true;
586 if (memberAlloc !=
No && memberAlloc != alloc)
604 if (destructor && tok->str() == varname)
608 deallocInDestructor =
true;
618 memberDealloc = dealloc;
629 if (allocInConstructor && !deallocInDestructor) {
642 "$symbol:" + classname +
"\n"
643 "$symbol:" + varname +
"\n"
644 "Class '" + classname +
"' is unsafe, '" + varname +
"' can leak by wrong usage.\n"
645 "The class '" + classname +
"' is unsafe, wrong usage can cause memory/resource leaks for '" + varname +
"'. This can for instance be fixed by adding proper cleanup in the destructor.",
CWE398,
Certainty::normal);
657 const int varid = classtok->
varId();
669 }
else if (
Token::Match(tok2,
"%type% :: %varid% =", varid) &&
690 logChecker(
"CheckMemoryLeakStructMember::check");
694 if (!var || (!var->isLocal() && !(var->isArgument() && var->scope())) || var->isStatic())
696 if (var->isReference() || (var->valueType() && var->valueType()->pointer > 1))
698 if (var->typeEndToken()->isStandardType())
711 if (
Token::Match(tok2,
"= %varid% [;=]", declarationId))
734 int indentlevel2 = 0;
736 auto deallocInFunction = [
this](
const Token* tok,
int structid) ->
bool {
742 bool deallocated =
false;
744 for (
const Token* tok2 = tok; tok2 != end; tok2 = tok2->
next()) {
745 if (
Token::Match(tok2,
"[(,] &| %varid% [,)]", structid)) {
751 if (
Token::Match(tok2,
"[(,] &| %varid% . %name% [,)]", structid)) {
762 auto isMemberAssignment = [](
const Token* varTok,
int varId) -> std::pair<const Token*, const Token*> {
763 if (varTok->
varId() != varId)
765 const Token* top = varTok;
774 while (dot && dot->
str() !=
".")
780 std::pair<const Token*, const Token*> assignToks;
785 for (
const Token *tok2 = tokStart; tok2 && tok2 != variable->
scope()->
bodyEnd; tok2 = tok2->
next()) {
786 if (tok2->str() ==
"{")
789 else if (tok2->str() ==
"}") {
790 if (indentlevel2 == 0)
801 else if ((assignToks = isMemberAssignment(tok2, variable->
declarationId())).first && assignToks.first->varId()) {
802 if (
getAllocationType(assignToks.second, assignToks.first->varId()) == AllocType::No)
814 const int structmemberid(assignToks.first->varId());
817 int indentlevel3 = indentlevel2;
818 for (
const Token *tok3 = tok2; tok3; tok3 = tok3->
next()) {
819 if (tok3->str() ==
"{")
822 else if (tok3->str() ==
"}") {
823 if (indentlevel3 == 0) {
833 if (indentlevel3 == 0)
840 if (tok3->str() ==
"return")
842 else if (tok3->str() ==
"{" || tok3->str() ==
"}")
846 if (!ret || !tok3 || tok3->str() !=
"}")
854 if (indentlevel2 == 0)
861 notvar(tok3->next()->astOperand2(), structmemberid)) {
863 tok3 = tok3->next()->link();
870 tok3 = tok3->next()->link();
874 else if (
ifvar(tok3, structmemberid,
"!=",
"0")) {
876 tok3 = tok3->next()->link();
879 int indentlevel4 = 0;
880 for (
const Token *tok4 = tok3; tok4; tok4 = tok4->
next()) {
881 if (tok4->str() ==
"{")
883 else if (tok4->str() ==
"}") {
885 if (indentlevel4 == 0)
893 if (indentlevel4 > 0)
898 else if ((tok3->scope()->type != Scope::ScopeType::eLambda || tok3->scope() == variable->
scope()) && tok3->str() ==
"return") {
900 if (!
Token::Match(tok3,
"return %varid% ;", structid) &&
902 !(
Token::Match(tok3,
"return %varid% . %var%", structid) && tok3->tokAt(3)->varId() == structmemberid) &&
903 !(
Token::Match(tok3,
"return %name% (") && tok3->astOperand1() && deallocInFunction(tok3->astOperand1(), structid))) {
912 }
else if (
Token::Match(tok3,
"= %var% . %varid% ;", structmemberid)) {
917 else if (tok3->str() ==
"goto")
922 if (deallocInFunction(tok3, structid))
975 const std::string& functionName = tok->str();
976 if ((tok->isCpp() && functionName ==
"delete") ||
977 functionName ==
"return")
985 const std::vector<const Token *> args =
getArguments(tok);
987 for (
const Token* arg : args) {
989 if (arg->isOp() && !(tok->isKeyword() && arg->str() ==
"*"))
991 while (arg->astOperand1()) {
994 arg = arg->astOperand1();
1004 if (bail && typeTok->
type() && typeTok->
type()->classScope &&
1005 typeTok->
type()->classScope->numConstructors == 0 &&
1006 typeTok->
type()->classScope->getDestructor() ==
nullptr) {
1014 if (tok->function()) {
1015 const Variable* argvar = tok->function()->getArgumentVar(argnr);
1034 const bool isNew = tok->isCpp() && tok->str() ==
"new";
1042 if (allocType ==
No)
1045 if (tok != tok->next()->astOperand1() && !isNew)
1054 const Token *parent = isNew ? tok->
astParent() : tok->next()->astParent();
1055 while (parent && parent->
isCast())
1064 if (!parent && warn) {
1070 }
else if (
Token::Match(parent,
"%comp%|!|,|%oror%|&&|:")) {
1073 if (parent->
str() ==
":") {
1102 logChecker(
"CheckMemoryLeakNoVar::checkForUnsafeArgAlloc");
1107 const Token* pointerType =
nullptr;
1108 const Token* functionCalled =
nullptr;
1112 const Function *func = tok2->function();
1117 }
else if (!isNothrow) {
1119 functionCalled = tok2;
1121 functionCalled = tok2;
1125 if (pointerType && functionCalled) {
1126 std::string functionName = functionCalled->
str();
1127 if (functionCalled->
strAt(1) ==
"<") {
1128 functionName +=
'<';
1129 for (
const Token* tok2 = functionCalled->
tokAt(2); tok2 != functionCalled->
next()->
link(); tok2 = tok2->next())
1130 functionName += tok2->str();
1131 functionName +=
'>';
1133 std::string objectTypeName;
1134 for (
const Token* tok2 = pointerType->
tokAt(2); tok2 != pointerType->
next()->
link(); tok2 = tok2->next())
1135 objectTypeName += tok2->str();
1155 const std::string factoryFunc = ptrType ==
"shared_ptr" ?
"make_shared" :
"make_unique";
1157 "$symbol:" + funcName +
"\n"
1158 "Unsafe allocation. If $symbol() throws, memory could be leaked. Use " + factoryFunc +
"<" + objType +
">() instead.",
const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok)
Is given syntax tree a variable comparison against value.
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
const Token * findLambdaEndToken(const Token *first)
find lambda function end token
int numberOfArguments(const Token *ftok)
Determines the number of arguments - if token is a function call or macro.
static const CWE CWE398(398U)
static bool notvar(const Token *tok, nonneg int varid)
static const CWE CWE772(772U)
static const CWE CWE771(771U)
static bool ifvar(const Token *tok, nonneg int varid, const std::string &comp, const std::string &rhs)
static const CWE CWE401(401U)
Check class variables, variables that are allocated in the constructor should be deallocated in the d...
void unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname)
void variable(const Scope *scope, const Token *tokVarname)
void checkPublicFunctions(const Scope *scope, const Token *classtok)
Public functions: possible double-allocation.
void publicAllocationError(const Token *tok, const std::string &varname)
CheckMemoryLeakInFunction detects when a function variable is allocated but not deallocated properly.
void checkReallocUsage()
Checking for a memory leak caused by improper realloc usage.
detect simple memory leaks (address not taken)
void returnValueNotUsedError(const Token *tok, const std::string &alloc)
void checkForUnusedReturnValue(const Scope *scope)
Check if a call to an allocation function like malloc() is made and its return value is not assigned.
void functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall)
void unsafeArgAllocError(const Token *tok, const std::string &funcName, const std::string &ptrType, const std::string &objType)
void checkForUnreleasedInputArgument(const Scope *scope)
Check if an input argument to a function is the return value of an allocation function like malloc(),...
void checkForUnsafeArgAlloc(const Scope *scope)
Check if an exception could cause a leak in an argument constructed with shared_ptr/unique_ptr.
detect simple memory leaks for struct members
void checkStructVariable(const Variable *const variable) const
bool isMalloc(const Variable *variable) const
Is local variable allocated with malloc?
AllocType functionReturnType(const Function *func, std::list< const Function * > *callstack=nullptr) const
What type of allocated memory does the given function return?
void memoryLeak(const Token *tok, const std::string &varname, AllocType alloctype) const
void deallocuseError(const Token *tok, const std::string &varname) const
AllocType getAllocationType(const Token *tok2, nonneg int varid, std::list< const Function * > *callstack=nullptr) const
Get type of allocation at given position.
AllocType getDeallocationType(const Token *tok, nonneg int varid) const
Get type of deallocation at given position.
AllocType getReallocationType(const Token *tok2, nonneg int varid) const
Get type of reallocation at given position.
bool isReopenStandardStream(const Token *tok) const
Check if token reopens a standard stream.
const Settings *const mSettings_
Enabled standards.
const Tokenizer *const mTokenizer_
For access to the tokens.
void resourceLeakError(const Token *tok, const std::string &varname) const
Report that there is a resource leak (fopen/popen/etc)
void mismatchAllocDealloc(const std::list< const Token * > &callstack, const std::string &varname) const
bool isOpenDevNull(const Token *tok) const
Check if token opens /dev/null.
ErrorLogger *const mErrorLogger_
ErrorLogger used to report errors.
void reportErr(const Token *tok, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const
Report error.
AllocType
What type of allocation are used.
void memleakUponReallocFailureError(const Token *tok, const std::string &reallocfunction, const std::string &varname) const
void memleakError(const Token *tok, const std::string &varname) const
Report that there is a memory leak (new/malloc/etc)
void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg)
report an error
const Settings *const mSettings
static void writeToErrorList(const ErrorMessage &errmsg)
Write given error to stdout in xml format.
const Tokenizer *const mTokenizer
void logChecker(const char id[])
log checker
virtual void reportErr(const ErrorMessage &msg)=0
Information about found errors and warnings is directed here.
Wrapper for error messages, provided by reportErr()
AccessControl access
public/protected/private
const Scope * functionScope
scope of function body
Type type
constructor, destructor, ...
const Token * arg
function argument start '('
bool isDestructor() const
bool isConstructor() const
bool isAttributeNothrow() const
const Container * detectContainerOrIterator(const Token *typeStart, bool *isIterator=nullptr, bool withoutStd=false) const
int getAllocId(const Token *tok, int arg) const
get allocation id for function
static bool ismemory(const int id)
is allocation type memory?
int getDeallocId(const Token *tok, int arg) const
get deallocation id for function
bool isLeakIgnore(const std::string &functionName) const
bool isnotnoreturn(const Token *ftok) const
int getReallocId(const Token *tok, int arg) const
get reallocation id for function
const AllocFunc * getAllocFuncInfo(const Token *tok) const
get allocation info for function
const AllocFunc * getReallocFuncInfo(const Token *tok) const
get reallocation info for function
int deallocId(const char name[]) const
get deallocation id for function by name (deprecated, use other alloc)
const PodType * podtype(const std::string &name) const
const AllocFunc * getDeallocFuncInfo(const Token *tok) const
get deallocation info for function
const Container * detectContainer(const Token *typeStart) const
std::list< Function > functionList
std::list< Variable > varlist
const Function * getDestructor() const
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
nonneg int numConstructors
bool hasLib(const std::string &lib) const
Is library specified?
bool isPremiumEnabled(const char id[]) const
Is checker id enabled by premiumArgs.
SimpleEnableGroup< Certainty > certainty
SimpleEnableGroup< Severity > severity
bool isEnabled(T flag) const
const std::vector< const Variable * > & variableList() const
std::vector< const Scope * > functionScopes
Fast access to function scopes.
std::vector< const Scope * > classAndStructScopes
Fast access to class and struct scopes.
The token list that the TokenList generates is a linked-list of this class.
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
const std::string & originalName() const
static const Token * findmatch(const Token *const startTok, const char pattern[], const nonneg int varId=0)
bool hasKnownIntValue() const
MathLib::bigint getKnownIntValue() const
const std::string & strAt(int index) const
void astOperand1(Token *tok)
void function(const Function *f)
Associate this token with given function.
std::string expressionString() const
bool isUnaryOp(const std::string &s) const
const Token * tokAt(int index) const
void astOperand2(Token *tok)
void link(Token *linkToToken)
Create link to given token.
const Token * linkAt(int index) const
void type(const ::Type *t)
Associate this token with given type.
bool isStandardType() const
void variable(const Variable *v)
Associate this token with given variable.
const Token * nextArgument() const
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
void astParent(Token *tok)
bool isScopeNoReturn(const Token *endScopeToken, bool *unknown=nullptr) const
Check if inner scope ends with a call to a noreturn function.
TokenList list
Token list: stores all tokens.
bool isC() const
Is the code C.
const SymbolDatabase * getSymbolDatabase() const
bool isCPP() const
Is the code CPP.
std::vector< BaseInfo > derivedFrom
enum ValueType::Type type
MathLib::bigint typeSize(const Platform &platform, bool p=false) const
Information about a member variable.
bool isArgument() const
Is variable a function argument.
bool isArrayOrPointer() const
Is array or pointer variable.
bool isLocal() const
Is variable local.
const Type * type() const
Get Type pointer of known type.
const Scope * scope() const
Get Scope pointer of enclosing scope.
const Scope * typeScope() const
Get Scope pointer of known type.
const std::string & name() const
Get name string.
bool isPointerArray() const
Is variable an array of pointers.
const Token * nameToken() const
Get name token.
bool isPrivate() const
Is variable private.
nonneg int declarationId() const
Get declaration ID (varId used for variable in its declaration).
const Token * typeStartToken() const
Get type start token.
bool isPointer() const
Is pointer variable.
bool isStatic() const
Is variable static.
const ValueType * valueType() const
Severity
enum class for severity.
@ error
Programming error.
static constexpr char CWE[]