38 #include <unordered_map>
61 logChecker(
"CheckFunctions::checkProhibitedFunctions");
74 "Obsolete function 'alloca' called. In C99 and later it is recommended to use a variable length array instead.\n"
75 "The obsolete function 'alloca' is called. In C99 and later it is recommended to use a variable length array or "
76 "a dynamically allocated array instead. The function 'alloca' is dangerous for many reasons "
77 "(http://stackoverflow.com/questions/1018853/why-is-alloca-not-considered-good-practice and http://linux.die.net/man/3/alloca).");
81 "Obsolete function 'alloca' called.\n"
82 "The obsolete function 'alloca' is called. In C++11 and later it is recommended to use std::array<> or "
83 "a dynamically allocated array instead. The function 'alloca' is dangerous for many reasons "
84 "(http://stackoverflow.com/questions/1018853/why-is-alloca-not-considered-good-practice and http://linux.die.net/man/3/alloca).");
86 if (tok->function() && tok->function()->hasBody())
106 logChecker(
"CheckFunctions::invalidFunctionUsage");
112 const Token *
const functionToken = tok;
113 const std::vector<const Token *> arguments =
getArguments(tok);
114 for (
int argnr = 1; argnr <= arguments.size(); ++argnr) {
115 const Token *
const argtok = arguments[argnr-1];
139 if ((valueType->
type == ValueType::Type::CHAR || valueType->
type == ValueType::Type::WCHAR_T || (valueType->
type == ValueType::Type::RECORD &&
Token::Match(argtok,
"& %var% . %var% ,|)"))) &&
149 if (variable && variable->
isLocal()
150 && valueType && (valueType->
type == ValueType::Type::CHAR || valueType->
type == ValueType::Type::WCHAR_T)
161 varTok = varTok->
tokAt(1);
162 auto charsUntilFirstZero = 0;
165 varTok = varTok->
next();
168 varTok = varTok->
next();
171 ++charsUntilFirstZero;
177 && (count == -1 || (count > 0 && count <= charsUntilFirstZero))) {
180 }
else if (count > -1 &&
Token::Match(varTok,
"= %str%")) {
184 if (strSize > count && strTok->
str().find(
'\0') == std::string::npos)
197 std::ostringstream errmsg;
198 errmsg <<
"$symbol:" << functionName <<
'\n';
199 if (invalidValue && invalidValue->
condition)
201 <<
" or $symbol() argument nr " << argnr <<
" can have invalid value.";
203 errmsg <<
"Invalid $symbol() argument nr " << argnr <<
'.';
205 errmsg <<
" The value is " << std::setprecision(10) << (invalidValue->
isIntValue() ? invalidValue->
intvalue : invalidValue->
floatValue) <<
" but the valid values are '" << validstr <<
"'.";
207 errmsg <<
" The value is 0 or 1 (boolean) but the valid values are '" << validstr <<
"'.";
211 "invalidFunctionArg",
218 "invalidFunctionArg",
226 std::ostringstream errmsg;
227 errmsg <<
"$symbol:" << functionName <<
'\n';
228 errmsg <<
"Invalid $symbol() argument nr " << argnr <<
". A non-boolean value is required.";
234 std::ostringstream errmsg;
235 errmsg <<
"$symbol:" << functionName <<
'\n';
236 errmsg <<
"Invalid $symbol() argument nr " << argnr <<
". A nul-terminated string is required.";
250 logChecker(
"CheckFunctions::checkIgnoredReturnValue");
257 tok = tok->linkAt(1);
261 if (tok->varId() || tok->isKeyword() || tok->isStandardType() || !
Token::Match(tok,
"%name% ("))
273 if (!tok->scope()->isExecutable()) {
274 tok = tok->scope()->bodyEnd;
278 if ((!tok->function() || !
Token::Match(tok->function()->retDef,
"void %name%")) &&
279 tok->next()->astOperand1()) {
281 const bool warn = (tok->function() && tok->function()->isAttributeNodiscard()) ||
302 "$symbol:" +
function +
"\nError code from the return value of function $symbol() is not used.",
CWE252,
Certainty::normal);
312 logChecker(
"CheckFunctions::checkMissingReturn");
316 if (!
function || !function->hasBody())
320 if (function->type != Function::Type::eFunction && function->type != Function::Type::eOperatorEqual)
322 if (
Token::Match(function->retDef,
"%name% (") && function->retDef->isUpperCaseName())
336 for (
const Token *prev = gotoToken; gotoToken; gotoToken = gotoToken->
previous()) {
347 const Token *lastStatement =
nullptr;
348 while ((tok = tok->
previous()) !=
nullptr) {
349 if (tok->
str() ==
")")
351 if (tok->
str() ==
"{")
352 return lastStatement ? lastStatement : tok->
next();
353 if (tok->
str() ==
"}") {
354 for (
const Token *prev = tok->
link()->previous(); prev && prev->scope() == tok->
scope() && !
Token::Match(prev,
"[;{}]"); prev = prev->previous()) {
355 if (prev->isKeyword() &&
Token::Match(prev,
"return|throw"))
360 if (tok->
scope()->type == Scope::ScopeType::eSwitch) {
362 bool hasDefault =
false;
363 bool reachable =
false;
364 for (
const Token *switchToken = tok->
link()->next(); switchToken != tok; switchToken = switchToken->
next()) {
371 if (switchToken->isKeyword() &&
Token::Match(switchToken,
"return|throw"))
379 else if (switchToken->str() ==
"{" && (switchToken->scope()->isLoopScope() || switchToken->scope()->type == Scope::ScopeType::eSwitch))
380 switchToken = switchToken->
link();
384 }
else if (tok->
scope()->type == Scope::ScopeType::eIf) {
385 const Token *condition = tok->
scope()->classDef->next()->astOperand2();
389 }
else if (tok->
scope()->type == Scope::ScopeType::eElse) {
411 lastStatement = tok->
next();
419 "Found an exit path from function with non-void return type that has missing return statement",
CWE758,
Certainty::normal);
432 logChecker(
"CheckFunctions::checkMathFunctions");
439 if (printWarnings &&
Token::Match(tok,
"%name% ( !!)")) {
440 if (tok->strAt(-1) !=
"."
441 &&
Token::Match(tok,
"log|logf|logl|log10|log10f|log10l|log2|log2f|log2l ( %num% )")) {
442 const std::string& number = tok->strAt(2);
446 }
else if (
Token::Match(tok,
"log1p|log1pf|log1pl ( %num% )")) {
447 const std::string& number = tok->strAt(2);
453 else if (
Token::Match(tok,
"atan2|atan2f|atan2l ( %num% , %num% )")) {
464 else if (
Token::Match(tok,
"pow|powf|powl ( %num% , %num% )")) {
490 else if (numParam == 2)
516 logChecker(
"CheckFunctions::memsetZeroBytes");
522 const std::vector<const Token *> &arguments =
getArguments(tok);
525 const Token* lastParamTok = arguments[2];
535 const std::string summary(
"memset() called to fill 0 bytes.");
536 const std::string verbose(summary +
" The second and third arguments might be inverted."
537 " The function memset ( void * ptr, int value, size_t num ) sets the"
538 " first num bytes of the block of memory pointed by ptr to the specified value.");
554 if (!printWarning && !printPortability)
557 logChecker(
"CheckFunctions::memsetInvalid2ndParam");
565 const std::vector<const Token *> args =
getArguments(tok);
566 if (args.size() != 3)
570 const Token *
const secondParamTok = args[1];
575 if (printPortability &&
astIsFloat(secondParamTok,
false)) {
579 if (printWarning && secondParamTok->
isNumber()) {
583 if (value < sCharMin || value > uCharMax)
592 const std::string message(
"The 2nd memset() argument '" + var_value +
593 "' is a float, its representation is implementation defined.");
594 const std::string verbose(message +
" memset() is used to set each byte of a block of memory to a specific value and"
595 " the actual representation of a floating-point value is implementation defined.");
601 const std::string message(
"The 2nd memset() argument '" + value +
"' doesn't fit into an 'unsigned char'.");
602 const std::string verbose(message +
" The 2nd parameter is passed as an 'int', but the function fills the block of memory using the 'unsigned char' conversion of this value.");
615 bool insideNew =
false;
617 if (!tok->scope() || !tok->scope()->isExecutable())
620 if (tok->str() ==
"new")
622 else if (tok->str() ==
";")
630 if (tok->varId() != 0 || tok->type() || tok->isStandardType())
633 if (tok->linkAt(1)->strAt(1) ==
"(")
654 if (functionName.empty())
666 const Token* start = tok;
668 start = start->
tokAt(-2);
674 "checkLibraryFunction",
675 "--check-library: There is no matching configuration for function " + functionName +
"()");
690 logChecker(
"CheckFunctions::returnLocalStdMove");
698 for (
const Token* ret : rets) {
716 "returnStdMoveLocal",
717 "Using std::move for returning object by-value from function will affect copy elision optimization."
718 " More: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-return-move-local");
726 logChecker(
"CheckFunctions::useStandardLibrary");
729 if (scope.type != Scope::ScopeType::eFor)
732 const Token *forToken = scope.classDef;
749 const auto idxVarId = idxToken->
varId();
757 const auto& secondOp = condToken->
str();
758 const bool isLess =
"<" == secondOp &&
761 const bool isMore =
">" == secondOp &&
765 if (!(isLess || isMore))
770 const bool plusOne = stepToken->
isBinaryOp() && stepToken->
str() ==
"+=" &&
773 if (!inc && !plusOne)
778 const Token *tok = scope.bodyStart;
779 const std::string memcpyName = tok->
isCpp() ?
"std::memcpy" :
"memcpy";
781 if (
Token::Match(tok,
"{ (| reinterpret_cast < uint8_t|int8_t|char|void * > ( %var% ) )| [ %varid% ] = "
782 "(| reinterpret_cast < const| uint8_t|int8_t|char|void * > ( %var% ) )| [ %varid% ] ; }", idxVarId)) {
788 if (
Token::Match(tok,
"{ ( ( uint8_t|int8_t|char|void * ) (| %var% ) )| [ %varid% ] = "
789 "( ( const| uint8_t|int8_t|char|void * ) (| %var% ) )| [ %varid% ] ; }", idxVarId)) {
795 const static std::string memsetName = tok->
isCpp() ?
"std::memset" :
"memset";
797 if (
Token::Match(tok,
"{ ( ( uint8_t|int8_t|char|void * ) (| %var% ) )| [ %varid% ] = %char%|%num% ; }", idxVarId)) {
803 if (
Token::Match(tok,
"{ ( ( uint8_t|int8_t|char|void * ) (| %var% ) )| [ %varid% ] = "
804 "( const| uint8_t|int8_t|char ) (| %char%|%num% )| ; }", idxVarId)) {
810 if (
Token::Match(tok,
"{ (| reinterpret_cast < uint8_t|int8_t|char|void * > ( %var% ) )| [ %varid% ] = "
811 "(| static_cast < const| uint8_t|int8_t|char > ( %char%|%num% ) )| ; }", idxVarId)) {
817 if (
Token::Match(tok,
"{ (| reinterpret_cast < uint8_t|int8_t|char|void * > ( %var% ) )| [ %varid% ] = "
818 "%char%|%num% ; }", idxVarId)) {
828 "useStandardLibrary",
829 "Consider using " + expected +
" instead of loop.");
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
bool astIsBool(const Token *tok)
Is expression of boolean type?
Token * getInitTok(Token *tok)
Library::Container::Action astContainerAction(const Token *tok, const Token **ftok)
Token * getCondTok(Token *tok)
bool astIsFloat(const Token *tok, bool unknown)
Is expression of floating point type?
Token * getStepTok(Token *tok)
bool isVariablesChanged(const Token *start, const Token *end, int indirect, const std::vector< const Variable * > &vars, const Settings &settings)
bool isConstExpression(const Token *tok, const Library &library)
Library::Container::Yield astContainerYield(const Token *tok, const Token **ftok)
int numberOfArguments(const Token *ftok)
Determines the number of arguments - if token is a function call or macro.
#define WRONG_DATA(COND, TOK)
Use WRONG_DATA in checkers to mark conditions that check that data is correct.
static const CWE CWE252(252U)
static const CWE CWE758(758U)
static const CWE CWE687(687U)
static const CWE CWE477(477U)
static const CWE CWE686(686U)
static bool isForwardJump(const Token *gotoToken)
static const CWE CWE688(688U)
static const CWE CWE628(628U)
static const Token * checkMissingReturnScope(const Token *tok, const Library &library)
Check for bad function usage.
void checkMissingReturn()
Check for missing "return"
void checkProhibitedFunctions()
Check for functions that should not be used.
void memsetZeroBytes()
Check for filling zero bytes with memset()
void ignoredReturnErrorCode(const Token *tok, const std::string &function)
void ignoredReturnValueError(const Token *tok, const std::string &function)
void invalidFunctionArgError(const Token *tok, const std::string &functionName, int argnr, const ValueFlow::Value *invalidValue, const std::string &validstr)
void memsetZeroBytesError(const Token *tok)
void useStandardLibrary()
void invalidFunctionArgStrError(const Token *tok, const std::string &functionName, nonneg int argnr)
void checkIgnoredReturnValue()
Check for ignored return values.
void missingReturnError(const Token *tok)
void memsetValueOutOfRangeError(const Token *tok, const std::string &value)
void invalidFunctionUsage()
Invalid function usage (invalid input value / overlapping data)
void checkLibraryMatchFunctions()
–check-library: warn for unconfigured function calls
void mathfunctionCallWarning(const Token *tok, const nonneg int numParam=1)
void invalidFunctionArgBoolError(const Token *tok, const std::string &functionName, int argnr)
void useStandardLibraryError(const Token *tok, const std::string &expected)
void memsetInvalid2ndParam()
Check for invalid 2nd parameter of memset()
void checkMathFunctions()
Check for parameters given to math function that do not make sense
void copyElisionError(const Token *tok)
void returnLocalStdMove()
Check for copy elision by RVO|NRVO
void memsetFloatError(const Token *tok, const std::string &var_value)
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 std::vector< const Token * > findReturns(const Function *f)
static bool returnsReference(const Function *function, bool unknown=false, bool includeRValueRef=false)
static bool returnsVoid(const Function *function, bool unknown=false)
Library definitions handling.
const Container * detectContainerOrIterator(const Token *typeStart, bool *isIterator=nullptr, bool withoutStd=false) const
const std::string & validarg(const Token *ftok, int argnr) const
bool isIntArgValid(const Token *ftok, int argnr, const MathLib::bigint argvalue) const
bool isnoreturn(const Token *ftok) const
bool isboolargbad(const Token *ftok, int argnr) const
bool isnotnoreturn(const Token *ftok) const
UseRetValType getUseRetValType(const Token *ftok) const
const AllocFunc * getAllocFuncInfo(const Token *tok) const
get allocation info for function
const WarnInfo * getWarnInfo(const Token *ftok) const
bool isargstrz(const Token *ftok, int argnr) const
TypeCheck getTypeCheck(std::string check, std::string typeName) const
const PodType * podtype(const std::string &name) const
std::string getFunctionName(const Token *ftok) const
Get function name for function call.
bool isNotLibraryFunction(const Token *ftok) const
std::unordered_map< std::string, Function > functions
static bigint toBigNumber(const std::string &str)
for conversion of numeric literals - for atoi-like conversions please use strToInt()
static bool isFloat(const std::string &str)
static bool isNullValue(const std::string &str)
Does the string represent the numerical value of 0? In case leading or trailing white space is provid...
static bool isNegative(const std::string &str)
static bool isInt(const std::string &str)
static double toDoubleNumber(const std::string &str)
for conversion of numeric literals
Function * function
function info for this function
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
bool checkLibrary
Check for incomplete info in library files?
bool isPremiumEnabled(const char id[]) const
Is checker id enabled by premiumArgs.
bool daca
Are we running from DACA script?
SimpleEnableGroup< Severity > severity
Standards standards
Struct contains standards settings.
bool isEnabled(T flag) const
std::vector< const Scope * > functionScopes
Fast access to function scopes.
std::list< Scope > scopeList
Information about all namespaces/classes/structures.
The token list that the TokenList generates is a linked-list of this class.
bool hasKnownValue() const
const ValueFlow::Value * getValue(const MathLib::bigint val) const
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
bool hasKnownIntValue() const
MathLib::bigint getKnownIntValue() const
const Token * getValueTokenMinStrSize(const Settings &settings, MathLib::bigint *path=nullptr) const
const ValueType * valueType() const
const std::string & strAt(int index) const
void astOperand1(Token *tok)
std::string expressionString() const
static nonneg int getStrArraySize(const Token *tok)
const Token * tokAt(int index) 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 ValueFlow::Value * getInvalidValue(const Token *ftok, nonneg int argnr, const Settings &settings) const
void variable(const Variable *v)
Associate this token with given variable.
bool isComparisonOp() const
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)
const Token * tokens() const
static bool isOneNumber(const std::string &s)
Helper function to check whether number is one (1 or 0.1E+1 or 1E+0) or not?
bool isC() const
Is the code C.
const SymbolDatabase * getSymbolDatabase() const
bool isCPP() const
Is the code CPP.
bool errorSeverity() const
double floatValue
float value
const Token * condition
Condition that this value depends on.
long long intvalue
int value (or sometimes bool value?)
bool isInconclusive() const
enum ValueType::Type type
Reference reference
Is the outermost indirection of this type a reference or rvalue.
Information about a member variable.
bool isLocal() const
Is variable local.
const Token * declEndToken() const
Get end token of variable declaration E.g.
bool isGlobal() const
Is variable global.
bool isConst() const
Is variable const.
bool isArray() const
Is variable an array.
@ portability
Portability warning.
@ information
Checking information.
@ performance
Performance warning.
@ error
Programming error.
std::string eitherTheConditionIsRedundant(const Token *condition)
enum Standards::cppstd_t cpp