36 #include <unordered_set>
116 if (tok->
str() ==
"+")
120 if (tok->
str() ==
"-")
136 for (std::list<ValueFlow::Value>::const_iterator it = tok->
values().cbegin(); it != tok->
values().cend(); ++it) {
152 if (tok->
str() ==
"+")
183 if (op->
str() ==
"[")
197 for (
const Token *tok = start; tok && tok != scope->
bodyEnd; tok = tok->
next()) {
198 if (tok->varId() == varId)
216 logChecker(
"CheckAutoVariables::assignFunctionArg");
222 if (tok->astParent())
231 if (vartok->
variable()->isPointer() && printWarning)
252 if (vt->container && vt->container->stdStringLike)
255 return std::any_of(vt->typeScope->functionList.begin(), vt->typeScope->functionList.end(), [](
const Function& f) {
256 return f.name() ==
"operator=";
266 logChecker(
"CheckAutoVariables::autoVariables");
274 tok = lambdaEndToken;
299 (tok->isCpp() &&
Token::Match(tok,
"delete [| ]| (| %var%|%str% !!["))) {
305 else if (tok->variable() && tok->variable()->isPointer()) {
307 if (v.isImpossible())
317 (tok->isCpp() &&
Token::Match(tok,
"delete [| ]| (| & %var% !!["))) {
330 for (
const Token *tok = startToken; tok; tok = tok->
next()) {
331 if (tok->str() ==
"}" && tok->scope()->type == Scope::ScopeType::eFunction)
339 const Token *lhs = tok;
346 const Token *e = expr;
347 while (e->
str() !=
"=" && lhs->
str() == e->
str()) {
351 if (lhs->
str() ==
"=")
360 tok = tok->linkAt(2);
371 "Address of local auto-variable assigned to a function parameter.\n"
372 "Dangerous assignment - the function parameter is assigned the address of a local "
373 "auto-variable. Local auto-variables are reserved from the stack which "
374 "is freed when the function ends. So the pointer to a local variable "
378 "Address of local auto-variable assigned to a function parameter.\n"
379 "Function parameter is assigned the address of a local auto-variable. "
380 "Local auto-variables are reserved from the stack which is freed when "
381 "the function ends. The address is invalid after the function ends and it "
382 "might 'leak' from the function through the parameter.",
392 "uselessAssignmentArg",
400 "uselessAssignmentPtrArg",
401 "Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?",
CWE398,
Certainty::normal);
422 if (tok->
scope() && !tok->
scope()->isClassOrStructOrUnion() && tok->
scope()->isNestedIn(scope))
431 return argScope && argScope->isNestedIn(scope);
460 for (
const Token* tok2 = decl.first; tok2 != decl.second; tok2 = tok2->
next())
493 if (!varDeclEndToken)
553 for (
const Token *tok = start; tok && tok != end; tok = tok->
next()) {
557 if (!printInconclusive && lt.inconclusive)
559 const Variable* var = lt.token->variable();
571 }
else if (
Token::Match(tok->previous(),
"&|&& %var% =") && tok->astParent() == tok->next() &&
572 tok->variable() && tok->variable()->nameToken() == tok &&
573 tok->variable()->declarationId() == tok->varId() && tok->variable()->isStatic() &&
574 !tok->variable()->isArgument()) {
582 }
else if (tok->variable() && (tok->variable()->isReference() || tok->variable()->isRValueReference())) {
584 if (!printInconclusive && lt.inconclusive)
586 const Token * tokvalue = lt.token;
595 std::unordered_set<const Token*> exprs;
597 if (!val.isLocalLifetimeValue() && !val.isSubFunctionLifetimeValue())
599 if (!printInconclusive && val.isInconclusive())
602 if (!exprs.insert(parent).second)
605 const Token * tokvalue = lt.token;
606 if (val.isLocalLifetimeValue()) {
612 if (tokvalue->
exprId() == tok->exprId() && !(tok->variable() && tok->variable()->isArray()) &&
634 const Token * tok2 = tok;
640 }
else if (tok->variable() && tok->variable()->declarationId() == tok->varId()) {
641 var = tok->variable();
647 nextTok = tok->
next();
648 if (var && !var->
isLocal() && !var->
isArgument() && !(val.tokvalue && val.tokvalue->variable() && val.tokvalue->variable()->isStatic()) &&
650 tok->
scope()->bodyEnd,
661 if (lambdaEndToken) {
663 tok = lambdaEndToken;
665 if (tok->str() ==
"{" && tok->scope()) {
670 for (
const Function& f:tok->scope()->functionList) {
682 logChecker(
"CheckAutoVariables::checkVarLifetime");
696 errorPath.emplace_back(tok,
"");
705 errorPath.emplace_back(tok,
"");
714 errorPath.emplace_back(tempTok,
"Temporary created here.");
715 errorPath.emplace_back(tok,
"");
718 "danglingTemporaryLifetime",
719 msg +
" that is a temporary.",
729 std::string msg =
"Non-local variable '" + tokName +
"' will use " +
lifetimeMessage(tok, val, errorPath);
730 errorPath.emplace_back(tok,
"");
736 errorPath.emplace_back(tok,
"");
743 errorPath.emplace_back(tok,
"");
750 std::string tokName = tok ? tok->
str() :
"x";
751 std::string varName = var ? var->
name() :
"y";
752 std::string msg =
"Non-local reference variable '" + tokName +
"' to local variable '" + varName +
"'";
753 errorPath.emplace_back(tok,
"");
759 errorPath.emplace_back(tok,
"");
768 std::string type =
"an auto-variable";
770 type =
"a string literal";
772 type =
"a pointer pointing to a string literal";
775 type =
"a global variable";
777 type =
"a static variable";
785 "autovarInvalidDeallocation",
786 "Deallocation of " + type +
" results in undefined behaviour.\n"
787 "The deallocation of " + type +
" results in undefined behaviour. You should only free memory "
bool astIsContainerView(const Token *tok)
bool exprDependsOnThis(const Token *expr, bool onVar, nonneg int depth)
bool isTemporary(const Token *tok, const Library *library, bool unknown)
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
bool astIsRHS(const Token *tok)
const Token * findLambdaEndToken(const Token *first)
find lambda function end token
const Token * nextAfterAstRightmostLeaf(const Token *tok)
const Token * getParentLifetime(const Token *tok)
Library::Container::Yield astContainerYield(const Token *tok, const Token **ftok)
bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth)
static const CWE CWE398(398U)
static bool isArrayVar(const Token *tok)
static bool isDeadScope(const Token *tok, const Scope *scope)
static bool isDeadTemporary(const Token *tok, const Token *expr, const Library *library)
static const Variable * getParentVar(const Token *tok)
static bool isAutoVar(const Token *tok)
static const CWE CWE590(590U)
static int getPointerDepth(const Token *tok)
static bool isEscapedReference(const Variable *var)
static bool isDanglingSubFunction(const Token *tokvalue, const Token *tok)
static bool isAutoVarArray(const Token *tok)
static bool isAssignedToNonLocal(const Token *tok)
static bool isInScope(const Token *tok, const Scope *scope)
static bool isAddressOfLocalVariable(const Token *expr)
static bool isAutoVariableRHS(const Token *tok)
static bool isArrayArg(const Token *tok, const Settings &settings)
static bool hasOverloadedAssignment(const Token *tok, bool &inconclusive)
static const CWE CWE562(562U)
static bool isNonReferenceArg(const Token *tok)
static bool isPtrArg(const Token *tok)
static bool isRefPtrArg(const Token *tok)
static bool variableIsUsedInScope(const Token *start, nonneg int varId, const Scope *scope)
static bool isLocalContainerBuffer(const Token *tok)
Various small checks for automatic variables.
void errorUselessAssignmentPtrArg(const Token *tok)
void errorReturnReference(const Token *tok, ErrorPath errorPath, bool inconclusive)
void errorReturnDanglingLifetime(const Token *tok, const ValueFlow::Value *val)
void errorInvalidLifetime(const Token *tok, const ValueFlow::Value *val)
void errorDanglingTemporaryLifetime(const Token *tok, const ValueFlow::Value *val, const Token *tempTok)
void checkVarLifetimeScope(const Token *start, const Token *end)
void errorDanglingTempReference(const Token *tok, ErrorPath errorPath, bool inconclusive)
void errorUselessAssignmentArg(const Token *tok)
void errorDanglingReference(const Token *tok, const Variable *var, ErrorPath errorPath)
void errorAutoVariableAssignment(const Token *tok, bool inconclusive)
void assignFunctionArg()
assign function argument
void errorDanglngLifetime(const Token *tok, const ValueFlow::Value *val)
bool diag(const Token *tokvalue)
returns true if tokvalue has already been diagnosed
bool checkAutoVariableAssignment(const Token *expr, bool inconclusive, const Token *startToken=nullptr)
Check variable assignment.
void autoVariables()
Check auto variables.
void errorInvalidDeallocation(const Token *tok, const ValueFlow::Value *val)
std::set< const Token * > mDiagDanglingTemp
void errorReturnTempReference(const Token *tok, ErrorPath errorPath, bool inconclusive)
void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg)
report an error
const Settings *const mSettings
ErrorPath getErrorPath(const Token *errtok, const ValueFlow::Value *value, std::string bug) const
const Tokenizer *const mTokenizer
void logChecker(const char id[])
log checker
static bool returnsReference(const Function *function, bool unknown=false, bool includeRValueRef=false)
static bool returnsStandardType(const Function *function, bool unknown=false)
Library definitions handling.
bool isentrypoint(const std::string &func) const
const AllocFunc * getDeallocFuncInfo(const Token *tok) const
get deallocation info for function
std::vector< Scope * > nestedList
static Function * nestedInFunction(const Scope *scope)
Function * function
function info for this function
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
This is just a container for general settings so that we don't need to pass individual values to func...
bool isPremiumEnabled(const char id[]) const
Is checker id enabled by premiumArgs.
SimpleEnableGroup< Certainty > certainty
SimpleEnableGroup< Severity > severity
bool isEnabled(T flag) const
std::vector< const Scope * > functionScopes
Fast access to function 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.
nonneg int exprId() const
const std::string & originalName() const
static const Token * findmatch(const Token *const startTok, const char pattern[], const nonneg int varId=0)
static std::pair< const Token *, const Token * > typeDecl(const Token *tok, bool pointedToType=false)
const ValueType * valueType() const
void astOperand1(Token *tok)
std::string expressionString() const
bool isUnaryOp(const std::string &s) const
static const Token * findsimplematch(const Token *const startTok, const char(&pattern)[count])
const Token * tokAt(int index) const
Token::Type tokType() const
void astOperand2(Token *tok)
void scope(const Scope *s)
Associate this token with given scope.
void link(Token *linkToToken)
Create link to given token.
const Token * linkAt(int index) const
void variable(const Variable *v)
Associate this token with given variable.
const std::list< ValueFlow::Value > & values() 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)
const SymbolDatabase * getSymbolDatabase() const
const Token * tokvalue
token value - the token that has the value.
bool isInconclusive() const
enum ValueType::Type type
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
Information about a member variable.
bool isArgument() const
Is variable a function argument.
bool isExtern() const
Is variable extern.
bool isReference() const
Is reference variable.
bool isRValueReference() const
Is reference variable.
bool isLocal() const
Is variable local.
const Token * declEndToken() const
Get end token of variable declaration E.g.
const Type * type() const
Get Type pointer of known type.
const Scope * scope() const
Get Scope pointer of enclosing scope.
bool isGlobal() const
Is variable global.
const std::string & name() const
Get name string.
bool isArray() const
Is variable an array.
const Token * nameToken() const
Get name token.
nonneg int declarationId() const
Get declaration ID (varId used for variable in its declaration).
bool isPointer() const
Is pointer variable.
bool isStatic() const
Is variable static.
const ValueType * valueType() const
std::list< ErrorPathItem > ErrorPath
@ error
Programming error.
std::vector< LifetimeToken > getLifetimeTokens(const Token *tok, const Settings &settings, bool escape=false, Value::ErrorPath errorPath=Value::ErrorPath{})
std::string lifetimeMessage(const Token *tok, const Value *val, Value::ErrorPath &errorPath)
bool isLifetimeBorrowed(const Token *tok, const Settings &settings)
const Variable * getLifetimeVariable(const Token *tok, Value::ErrorPath &errorPath, const Settings &settings, bool *addressOf=nullptr)