46 for (
const auto &value: tok->
values()) {
48 return value.floatValue;
75 if (buf->
variable()->dimensions().size() > nr && buf->
variable()->dimensions()[nr].known) {
80 Severity::SeverityType::error,
81 "bughuntingArrayIndexOutOfBounds",
82 "Array index out of bounds, cannot determine that " + index->
expressionString() +
" is less than " + std::to_string(bufSize),
89 if (!isUnsigned && value.
isLessThan(dataBase, 0)) {
92 Severity::SeverityType::error,
93 "bughuntingArrayIndexNegative",
94 "Array index out of bounds, cannot determine that " + index->
expressionString() +
" is not negative",
113 if (!functionCallArguments)
116 const std::vector<const Token *> arguments =
getArguments(tok);
117 if (functionCallArguments->
argValues.size() != arguments.size())
121 int overflowArgument = 0;
125 const int argnr = argNrChecks.first;
127 if (argnr <= 0 || argnr > arguments.size() || checks.
minsizes.empty())
132 overflowArgument = argnr;
137 std::shared_ptr<ExprEngine::ArrayValue> arrayValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(argValue);
138 if (!arrayValue || arrayValue->size.size() != 1) {
140 overflowArgument = argnr;
149 overflowArgument = argnr;
153 if (
isLessThan(dataBase, arrayValue->size[0], otherValue)) {
154 overflowArgument = argnr;
160 overflowArgument = argnr;
165 const Token *
const str = arguments[minsize.
arg - 1];
167 overflowArgument = argnr;
173 overflowArgument = argnr;
177 std::shared_ptr<ExprEngine::ArrayValue> arrayValue2 = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(otherValue);
178 if (!arrayValue2 || arrayValue2->size.size() != 1) {
179 overflowArgument = argnr;
183 if (
isLessThan(dataBase, arrayValue->size[0], arrayValue2->size[0])) {
184 overflowArgument = argnr;
191 if (overflowArgument > 0)
195 if (overflowArgument == 0)
199 Severity::SeverityType::error,
200 "bughuntingBufferOverflow",
201 "Buffer read/write, when calling '" + tok->
previous()->
str() +
"' it cannot be determined that " + std::to_string(overflowArgument) +
getOrdinalText(overflowArgument) +
" argument is not overflowed",
218 if (f > 0.0f || f < 0.0f)
225 const char *
const id = (tok->
valueType() && tok->
valueType()->
isFloat()) ?
"bughuntingDivByZeroFloat" :
"bughuntingDivByZero";
228 Severity::SeverityType::error,
230 "There is division, cannot determine that there can't be a division by zero.",
237 #ifdef BUG_HUNTING_INTEGEROVERFLOW
248 if (bits == 0 || bits >= 60)
251 std::string errorMessage;
255 errorMessage =
"greater than " + std::to_string(v - 1);
257 if (!errorMessage.empty())
258 errorMessage +=
" or ";
259 errorMessage +=
"less than " + std::to_string(-v);
264 errorMessage =
"greater than " + std::to_string(maxValue);
266 if (!errorMessage.empty())
267 errorMessage +=
" or ";
268 errorMessage +=
"less than 0";
272 if (errorMessage.empty())
276 errorMessage =
"There is integer arithmetic, cannot determine that there can't be overflow (if result is " + errorMessage +
").";
279 errorMessage +=
" Note that unsigned integer overflow is defined and will wrap around.";
294 if (prev->str() ==
"}") {
296 const Token *elseEnd = prev;
306 if (scopeStart &&
Token::Match(prev,
"return|throw|continue|break"))
309 bool usedInRhs =
false;
311 if (tok->varId() == var->declarationId()) {
313 return ChildrenToVisit::done;
329 std::string uninitStructMember;
331 uninitStructMember = structValue->getUninitStructMember(dataBase);
334 if (!uninitStructMember.empty()) {
340 bool uninitData =
false;
341 if (!value.
isUninit(dataBase) && uninitStructMember.empty()) {
344 uninitData = arrayValue->data.size() >= 1 && arrayValue->data[0].value->isUninit(dataBase);
357 if (tok->
str() ==
"[" &&
362 if (tok->
astOperand1()->valueType()->container->stdStringLike)
364 bool pointerType =
false;
365 for (
const Token *typeTok = tok->
astOperand1()->valueType()->containerTypeToken;
Token::Match(typeTok,
"%name%|*|::|<"); typeTok = typeTok->next()) {
366 if (typeTok->str() ==
"<" && typeTok->link())
367 typeTok = typeTok->link();
368 if (typeTok->str() ==
"*")
378 if (tok->
variable()->isSmartPointer())
420 for (
const Token *t: tokens) {
421 if (t && t->valueType() && t->valueType()->pointer == 0 && t->valueType()->container)
452 bool inconclusive =
false;
470 if (uninitData && argvar && !argvar->
isConst()) {
475 if (!uninitStructMember.empty() && dataBase->
isC() && argvar && !argvar->
isConst()) {
480 }
else if (uninitData) {
486 }
else if (uninitData)
495 while (parent && parent->
str() ==
"[")
500 const std::string inconclusiveMessage(inconclusive ?
". It is inconclusive if there would be a problem in the function call." :
"");
502 if (!uninitStructMember.empty()) {
503 const std::string symbol = tok->
expressionString() +
"." + uninitStructMember;
505 Severity::SeverityType::error,
506 "bughuntingUninitStructMember",
507 "$symbol:" + symbol +
"\nCannot determine that '$symbol' is initialized" + inconclusiveMessage,
518 const std::string symbol = (tok->
varId() > 0) ? (
"$symbol:" + tok->
str() +
"\n") : std::string();
520 std::string constMessage;
521 std::string errorId =
"bughuntingUninit";
524 const Token *vartok = tok;
529 errorId +=
"NonConstArg";
530 constMessage =
" (you can use 'const' to say data must be initialized)";
536 Severity::SeverityType::error,
538 symbol +
"Cannot determine that '" + uninitexpr +
"' is initialized" + constMessage + inconclusiveMessage,
551 if (!parent || parent->
str() !=
"(")
573 bad =
"__cppcheck_low__(" + std::to_string(low) +
")";
579 bad =
"__cppcheck_high__(" + std::to_string(high) +
")";
584 Severity::SeverityType::error,
585 "bughuntingInvalidArgValue",
586 "There is function call, cannot determine that " + std::to_string(num) +
getOrdinalText(num) +
" argument value meets the attribute " + bad,
598 switch (invalidArgValue.type) {
602 bad =
"equals " + invalidArgValue.op1;
607 bad =
"less equal " + invalidArgValue.op1;
612 bad =
"less than " + invalidArgValue.op1;
617 bad =
"greater equal " + invalidArgValue.op1;
622 bad =
"greater than " + invalidArgValue.op1;
628 bad =
"range " + invalidArgValue.op1 +
"-" + invalidArgValue.op2;
633 dataBase->
reportError(tok, Severity::SeverityType::error,
"bughuntingInvalidArgValue",
"There is function call, cannot determine that " + std::to_string(num) +
getOrdinalText(num) +
" argument value is valid. Bad value: " + bad,
CWE(0),
false);
641 auto index0 = std::make_shared<ExprEngine::IntRange>(
"0", 0, 0);
642 for (
const auto &v: arrayValue.
read(index0)) {
643 if (v.second->isUninit(dataBase)) {
663 bool executable =
false;
664 std::string fullName = lhs->
variable()->name();
665 for (
const Scope *s = lhs->
variable()->nameToken()->scope(); s->type != Scope::ScopeType::eGlobal; s = s->nestedIn) {
666 if (s->isExecutable()) {
670 fullName = s->className +
"::" + fullName;
679 const std::string *
str;
680 if (type == TokenImpl::CppcheckAttributes::Type::LOW)
681 str = &it->second.minValue;
682 else if (type == TokenImpl::CppcheckAttributes::Type::HIGH)
683 str = &it->second.maxValue;
687 return !
str->empty();
694 if (getMinMaxValue(TokenImpl::CppcheckAttributes::Type::LOW, &low)) {
696 dataBase->
reportError(tok, Severity::SeverityType::error,
"bughuntingAssign",
"There is assignment, cannot determine that value is greater or equal with " + std::to_string(low),
CWE_INCORRECT_CALCULATION,
false);
700 if (getMinMaxValue(TokenImpl::CppcheckAttributes::Type::HIGH, &high)) {
702 dataBase->
reportError(tok, Severity::SeverityType::error,
"bughuntingAssign",
"There is assignment, cannot determine that value is lower or equal with " + std::to_string(high),
CWE_INCORRECT_CALCULATION,
false);
713 #ifdef BUG_HUNTING_INTEGEROVERFLOW
714 callbacks->push_back(integerOverflow);
716 callbacks->push_back(
uninit);
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
void visitAstNodes(T *ast, const TFunc &visitor)
Visit AST nodes recursively.
static void uninit(const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase)
static void checkAssignment(const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase)
static float getKnownFloatValue(const Token *tok, float def)
static void bufferOverflow(const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase)
static const CWE CWE_BUFFER_UNDERRUN(786U)
static const CWE CWE_BUFFER_OVERRUN(788U)
void addBughuntingChecks(std::vector< ExprEngine::Callback > *callbacks)
static bool isVariableAssigned(const Variable *var, const Token *tok, const Token *scopeStart=nullptr)
check if variable is unconditionally assigned
static bool isLessThan(ExprEngine::DataBase *dataBase, ExprEngine::ValuePtr lhs, ExprEngine::ValuePtr rhs)
static void arrayIndex(const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase)
static void divByZero(const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase)
static void checkFunctionCall(const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase)
ConditionalValue::Vector read(ValuePtr index) const
bool isTrue(const DataBase *dataBase) const
virtual bool isLessThan(const DataBase *dataBase, int value) const override
bool isGreaterThan(const DataBase *dataBase, int value) const override
virtual void reportError(const Token *tok, Severity::SeverityType severity, const char id[], const std::string &text, CWE cwe, bool inconclusive, bool incomplete=false, const std::string &functionName=std::string())=0
virtual bool isC() const =0
const Settings *const settings
const std::vector< ExprEngine::ValuePtr > argValues
virtual bool isGreaterThan(const DataBase *dataBase, int value) const
virtual bool isEqual(const DataBase *dataBase, int value) const
virtual bool isUninit(const DataBase *dataBase) const
virtual bool isLessThan(const DataBase *dataBase, int value) const
std::vector< MinSize > minsizes
bool isuninitargbad(const Token *ftok, int argnr, int indirect=0, bool *hasIndirect=nullptr) const
const std::string & validarg(const Token *ftok, int argnr) const
bool isnullargbad(const Token *ftok, int argnr) const
static std::vector< InvalidArgValue > getInvalidArgValues(const std::string &validExpr)
const Function * getFunction(const Token *ftok) const
static bigint toLongNumber(const std::string &str)
SimpleEnableGroup< Certainty::CertaintyLevel > certainty
std::map< std::string, VariableContracts > variableContracts
bool isEnabled(T flag) const
The token list that the TokenList generates is a linked-list of this class.
bool hasKnownValue() 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 isImpossibleIntValue(const MathLib::bigint val) const
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
bool isArithmeticalOp() const
static nonneg int getStrLength(const Token *tok)
const ValueType * valueType() const
void astOperand1(Token *tok)
std::string expressionString() const
const Token * tokAt(int index) const
void astOperand2(Token *tok)
void link(Token *linkToToken)
Create link to given token.
bool getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint *value) 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 Library::Container * container
If the type is a container defined in a cfg file, this is the used.
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
enum ValueType::Sign sign
Information about a member variable.
bool isArgument() const
Is variable a function argument.
bool isReference() const
Is reference variable.
bool isLocal() const
Is variable local.
bool isConst() const
Is variable const.
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 isInit() const
Is variable initialized in its declaration.
bool isPointer() const
Is pointer variable.
bool isStatic() const
Is variable static.
static const struct CWE CWE_USE_OF_UNINITIALIZED_VARIABLE(457U)
CWE id (Common Weakness Enumeration) See https://cwe.mitre.org/ for further reference.
static const struct CWE CWE_INCORRECT_CALCULATION(682U)
static std::string str(ExprEngine::ValuePtr val)
static int getIntBitsFromValueType(const ValueType *vt, const cppcheck::Platform &platform)
std::shared_ptr< Value > ValuePtr
@ FunctionCallArgumentValues
std::map< int, ArgumentChecks > argumentChecks
static const char * getOrdinalText(int i)
#define bailout(tokenlist, errorLogger, tok, what)