Refactorized Library

This commit is contained in:
PKEuS 2016-12-06 12:31:16 +01:00 committed by PKEuS
parent af1398900c
commit 2f6350a0d0
16 changed files with 207 additions and 188 deletions

View File

@ -128,7 +128,7 @@ const Token * astIsVariableComparison(const Token *tok, const std::string &comp,
return ret; return ret;
} }
bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const std::set<std::string> &constFunctions) bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const Library& library, bool pure)
{ {
if (tok1 == nullptr && tok2 == nullptr) if (tok1 == nullptr && tok2 == nullptr)
return true; return true;
@ -143,15 +143,15 @@ bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2
if (tok1->varId() != tok2->varId() || tok1->str() != tok2->str() || tok1->originalName() != tok2->originalName()) { if (tok1->varId() != tok2->varId() || tok1->str() != tok2->str() || tok1->originalName() != tok2->originalName()) {
if ((Token::Match(tok1,"<|>") && Token::Match(tok2,"<|>")) || if ((Token::Match(tok1,"<|>") && Token::Match(tok2,"<|>")) ||
(Token::Match(tok1,"<=|>=") && Token::Match(tok2,"<=|>="))) { (Token::Match(tok1,"<=|>=") && Token::Match(tok2,"<=|>="))) {
return isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand2(), constFunctions) && return isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand2(), library, pure) &&
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand1(), constFunctions); isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand1(), library, pure);
} }
return false; return false;
} }
if (macro && (tok1->isExpandedMacro() || tok2->isExpandedMacro())) if (macro && (tok1->isExpandedMacro() || tok2->isExpandedMacro()))
return false; return false;
if (tok1->isName() && tok1->next()->str() == "(" && tok1->str() != "sizeof") { if (tok1->isName() && tok1->next()->str() == "(" && tok1->str() != "sizeof") {
if (!tok1->function() && !Token::Match(tok1->previous(), ".|::") && constFunctions.find(tok1->str()) == constFunctions.end() && !tok1->isAttributeConst() && !tok1->isAttributePure()) if (!tok1->function() && !Token::Match(tok1->previous(), ".|::") && pure && !library.isFunctionConst(tok1->str(), true) && !tok1->isAttributeConst() && !tok1->isAttributePure())
return false; return false;
else if (tok1->function() && !tok1->function()->isConst() && !tok1->function()->isAttributeConst() && !tok1->function()->isAttributePure()) else if (tok1->function() && !tok1->function()->isConst() && !tok1->function()->isAttributeConst() && !tok1->function()->isAttributePure())
return false; return false;
@ -201,18 +201,18 @@ bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2
return false; return false;
} }
bool noncommutativeEquals = bool noncommutativeEquals =
isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand1(), constFunctions); isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand1(), library, pure);
noncommutativeEquals = noncommutativeEquals && noncommutativeEquals = noncommutativeEquals &&
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand2(), constFunctions); isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand2(), library, pure);
if (noncommutativeEquals) if (noncommutativeEquals)
return true; return true;
const bool commutative = tok1->astOperand1() && tok1->astOperand2() && Token::Match(tok1, "%or%|%oror%|+|*|&|&&|^|==|!="); const bool commutative = tok1->astOperand1() && tok1->astOperand2() && Token::Match(tok1, "%or%|%oror%|+|*|&|&&|^|==|!=");
bool commutativeEquals = commutative && bool commutativeEquals = commutative &&
isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand1(), constFunctions); isSameExpression(cpp, macro, tok1->astOperand2(), tok2->astOperand1(), library, pure);
commutativeEquals = commutativeEquals && commutativeEquals = commutativeEquals &&
isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand2(), constFunctions); isSameExpression(cpp, macro, tok1->astOperand1(), tok2->astOperand2(), library, pure);
// in c++, "a"+b might be different to b+"a" // in c++, "a"+b might be different to b+"a"
if (cpp && commutativeEquals && tok1->str() == "+" && if (cpp && commutativeEquals && tok1->str() == "+" &&
@ -224,7 +224,7 @@ bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2
return commutativeEquals; return commutativeEquals;
} }
bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions) bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const Library& library, bool pure)
{ {
if (!cond1 || !cond2) if (!cond1 || !cond2)
return false; return false;
@ -232,15 +232,15 @@ bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token
if (cond1->str() == "!") { if (cond1->str() == "!") {
if (cond2->str() == "!=") { if (cond2->str() == "!=") {
if (cond2->astOperand1() && cond2->astOperand1()->str() == "0") if (cond2->astOperand1() && cond2->astOperand1()->str() == "0")
return isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand2(), constFunctions); return isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand2(), library, pure);
if (cond2->astOperand2() && cond2->astOperand2()->str() == "0") if (cond2->astOperand2() && cond2->astOperand2()->str() == "0")
return isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand1(), constFunctions); return isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand1(), library, pure);
} }
return isSameExpression(cpp, true, cond1->astOperand1(), cond2, constFunctions); return isSameExpression(cpp, true, cond1->astOperand1(), cond2, library, pure);
} }
if (cond2->str() == "!") if (cond2->str() == "!")
return isOppositeCond(isNot, cpp, cond2, cond1, constFunctions); return isOppositeCond(isNot, cpp, cond2, cond1, library, pure);
if (!cond1->isComparisonOp() || !cond2->isComparisonOp()) if (!cond1->isComparisonOp() || !cond2->isComparisonOp())
return false; return false;
@ -249,11 +249,11 @@ bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token
// condition found .. get comparator // condition found .. get comparator
std::string comp2; std::string comp2;
if (isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand1(), constFunctions) && if (isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand1(), library, pure) &&
isSameExpression(cpp, true, cond1->astOperand2(), cond2->astOperand2(), constFunctions)) { isSameExpression(cpp, true, cond1->astOperand2(), cond2->astOperand2(), library, pure)) {
comp2 = cond2->str(); comp2 = cond2->str();
} else if (isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand2(), constFunctions) && } else if (isSameExpression(cpp, true, cond1->astOperand1(), cond2->astOperand2(), library, pure) &&
isSameExpression(cpp, true, cond1->astOperand2(), cond2->astOperand1(), constFunctions)) { isSameExpression(cpp, true, cond1->astOperand2(), cond2->astOperand1(), library, pure)) {
comp2 = cond2->str(); comp2 = cond2->str();
if (comp2[0] == '>') if (comp2[0] == '>')
comp2[0] = '<'; comp2[0] = '<';
@ -272,12 +272,12 @@ bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token
(comp1 == ">" && comp2 == "<")))); (comp1 == ">" && comp2 == "<"))));
} }
bool isConstExpression(const Token *tok, const std::set<std::string> &constFunctions) bool isConstExpression(const Token *tok, const Library& library, bool pure)
{ {
if (!tok) if (!tok)
return true; return true;
if (tok->isName() && tok->next()->str() == "(") { if (tok->isName() && tok->next()->str() == "(") {
if (!tok->function() && !Token::Match(tok->previous(), ".|::") && constFunctions.find(tok->str()) == constFunctions.end()) if (!tok->function() && !Token::Match(tok->previous(), ".|::") && !library.isFunctionConst(tok->str(), pure))
return false; return false;
else if (tok->function() && !tok->function()->isConst()) else if (tok->function() && !tok->function()->isConst())
return false; return false;
@ -287,7 +287,7 @@ bool isConstExpression(const Token *tok, const std::set<std::string> &constFunct
// bailout when we see ({..}) // bailout when we see ({..})
if (tok->str() == "{") if (tok->str() == "{")
return false; return false;
return isConstExpression(tok->astOperand1(),constFunctions) && isConstExpression(tok->astOperand2(),constFunctions); return isConstExpression(tok->astOperand1(), library, pure) && isConstExpression(tok->astOperand2(), library, pure);
} }
bool isWithoutSideEffects(bool cpp, const Token* tok) bool isWithoutSideEffects(bool cpp, const Token* tok)

View File

@ -22,10 +22,10 @@
#define astutilsH #define astutilsH
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include <set>
#include <string> #include <string>
class Settings; class Settings;
class Library;
class Token; class Token;
/** Is expression a 'signed char' if no promotion is used */ /** Is expression a 'signed char' if no promotion is used */
@ -53,7 +53,7 @@ std::string astCanonicalType(const Token *expr);
/** Is given syntax tree a variable comparison against value */ /** Is given syntax tree a variable comparison against value */
const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok=nullptr); const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok=nullptr);
bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const std::set<std::string> &constFunctions); bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const Library& library, bool pure);
/** /**
* Are two conditions opposite * Are two conditions opposite
@ -63,9 +63,9 @@ bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2
* @param cond2 condition2 * @param cond2 condition2
* @param constFunctions constFunctions * @param constFunctions constFunctions
*/ */
bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions); bool isOppositeCond(bool isNot, bool cpp, const Token * const cond1, const Token * const cond2, const Library& library, bool pure);
bool isConstExpression(const Token *tok, const std::set<std::string> &constFunctions); bool isConstExpression(const Token *tok, const Library& library, bool pure);
bool isWithoutSideEffects(bool cpp, const Token* tok); bool isWithoutSideEffects(bool cpp, const Token* tok);

View File

@ -351,13 +351,13 @@ void CheckCondition::comparisonError(const Token *tok, const std::string &bitop,
reportError(tok, Severity::style, "comparisonError", errmsg, CWE398, false); reportError(tok, Severity::style, "comparisonError", errmsg, CWE398, false);
} }
bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions) const bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token * const cond2, bool pure) const
{ {
if (!cond1 || !cond2) if (!cond1 || !cond2)
return false; return false;
// same expressions // same expressions
if (isSameExpression(_tokenizer->isCPP(), true, cond1, cond2, constFunctions)) if (isSameExpression(_tokenizer->isCPP(), true, cond1, cond2, _settings->library, pure))
return true; return true;
// bitwise overlap for example 'x&7' and 'x==1' // bitwise overlap for example 'x&7' and 'x==1'
@ -380,7 +380,7 @@ bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token *
if (!num2->isNumber() || MathLib::isNegative(num2->str())) if (!num2->isNumber() || MathLib::isNegative(num2->str()))
return false; return false;
if (!isSameExpression(_tokenizer->isCPP(), true, expr1, expr2, constFunctions)) if (!isSameExpression(_tokenizer->isCPP(), true, expr1, expr2, _settings->library, pure))
return false; return false;
const MathLib::bigint value1 = MathLib::toLongNumber(num1->str()); const MathLib::bigint value1 = MathLib::toLongNumber(num1->str());
@ -414,7 +414,7 @@ void CheckCondition::multiCondition()
break; break;
tok2 = tok2->tokAt(4); tok2 = tok2->tokAt(4);
if (isOverlappingCond(cond1, tok2->astOperand2(), _settings->library.functionpure)) if (isOverlappingCond(cond1, tok2->astOperand2(), true))
multiConditionError(tok2, cond1->linenr()); multiConditionError(tok2, cond1->linenr());
} }
} }
@ -502,7 +502,7 @@ void CheckCondition::oppositeInnerCondition()
const Token *cond1 = scope->classDef->next()->astOperand2(); const Token *cond1 = scope->classDef->next()->astOperand2();
const Token *cond2 = ifToken->next()->astOperand2(); const Token *cond2 = ifToken->next()->astOperand2();
if (isOppositeCond(false, _tokenizer->isCPP(), cond1, cond2, _settings->library.functionpure)) if (isOppositeCond(false, _tokenizer->isCPP(), cond1, cond2, _settings->library, true))
oppositeInnerConditionError(scope->classDef, cond2); oppositeInnerConditionError(scope->classDef, cond2);
} }
} }
@ -677,7 +677,7 @@ void CheckCondition::checkIncorrectLogicOperator()
// Opposite comparisons around || or && => always true or always false // Opposite comparisons around || or && => always true or always false
if ((tok->astOperand1()->isName() || tok->astOperand2()->isName()) && if ((tok->astOperand1()->isName() || tok->astOperand2()->isName()) &&
isOppositeCond(true, _tokenizer->isCPP(), tok->astOperand1(), tok->astOperand2(), _settings->library.functionpure)) { isOppositeCond(true, _tokenizer->isCPP(), tok->astOperand1(), tok->astOperand2(), _settings->library, true)) {
const bool alwaysTrue(tok->str() == "||"); const bool alwaysTrue(tok->str() == "||");
incorrectLogicOperatorError(tok, tok->expressionString(), alwaysTrue, false); incorrectLogicOperatorError(tok, tok->expressionString(), alwaysTrue, false);
@ -691,7 +691,7 @@ void CheckCondition::checkIncorrectLogicOperator()
((tok->str() == "||" && tok->astOperand2()->str() == "&&") || ((tok->str() == "||" && tok->astOperand2()->str() == "&&") ||
(tok->str() == "&&" && tok->astOperand2()->str() == "||"))) { (tok->str() == "&&" && tok->astOperand2()->str() == "||"))) {
const Token* tok2 = tok->astOperand2()->astOperand1(); const Token* tok2 = tok->astOperand2()->astOperand1();
if (isOppositeCond(true, _tokenizer->isCPP(), tok->astOperand1(), tok2, _settings->library.functionpure)) { if (isOppositeCond(true, _tokenizer->isCPP(), tok->astOperand1(), tok2, _settings->library, true)) {
std::string expr1(tok->astOperand1()->expressionString()); std::string expr1(tok->astOperand1()->expressionString());
std::string expr2(tok->astOperand2()->astOperand1()->expressionString()); std::string expr2(tok->astOperand2()->astOperand1()->expressionString());
std::string expr3(tok->astOperand2()->astOperand2()->expressionString()); std::string expr3(tok->astOperand2()->astOperand2()->expressionString());
@ -752,9 +752,9 @@ void CheckCondition::checkIncorrectLogicOperator()
if (inconclusive && !printInconclusive) if (inconclusive && !printInconclusive)
continue; continue;
if (isSameExpression(_tokenizer->isCPP(), true, comp1, comp2, _settings->library.functionpure)) if (isSameExpression(_tokenizer->isCPP(), true, comp1, comp2, _settings->library, true))
continue; // same expressions => only report that there are same expressions continue; // same expressions => only report that there are same expressions
if (!isSameExpression(_tokenizer->isCPP(), true, expr1, expr2, _settings->library.functionpure)) if (!isSameExpression(_tokenizer->isCPP(), true, expr1, expr2, _settings->library, true))
continue; continue;
const bool isfloat = astIsFloat(expr1, true) || MathLib::isFloat(value1) || astIsFloat(expr2, true) || MathLib::isFloat(value2); const bool isfloat = astIsFloat(expr1, true) || MathLib::isFloat(value1) || astIsFloat(expr2, true) || MathLib::isFloat(value2);
@ -1082,9 +1082,9 @@ void CheckCondition::checkInvalidTestForOverflow()
continue; continue;
const Token *termToken; const Token *termToken;
if (isSameExpression(_tokenizer->isCPP(), true, exprToken, calcToken->astOperand1(), _settings->library.functionpure)) if (isSameExpression(_tokenizer->isCPP(), true, exprToken, calcToken->astOperand1(), _settings->library, true))
termToken = calcToken->astOperand2(); termToken = calcToken->astOperand2();
else if (isSameExpression(_tokenizer->isCPP(), true, exprToken, calcToken->astOperand2(), _settings->library.functionpure)) else if (isSameExpression(_tokenizer->isCPP(), true, exprToken, calcToken->astOperand2(), _settings->library, true))
termToken = calcToken->astOperand1(); termToken = calcToken->astOperand1();
else else
continue; continue;

View File

@ -103,7 +103,7 @@ public:
private: private:
bool isOverlappingCond(const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions) const; bool isOverlappingCond(const Token * const cond1, const Token * const cond2, bool pure) const;
void assignIfError(const Token *tok1, const Token *tok2, const std::string &condition, bool result); void assignIfError(const Token *tok1, const Token *tok2, const std::string &condition, bool result);
void mismatchingBitAndError(const Token *tok1, const MathLib::bigint num1, const Token *tok2, const MathLib::bigint num2); void mismatchingBitAndError(const Token *tok1, const MathLib::bigint num1, const Token *tok2, const MathLib::bigint num2);
void badBitmaskCheckError(const Token *tok); void badBitmaskCheckError(const Token *tok);

View File

@ -233,7 +233,7 @@ void CheckIO::checkFileUsage()
if ((tok->str() == "ungetc" || tok->str() == "ungetwc") && fileTok) if ((tok->str() == "ungetc" || tok->str() == "ungetwc") && fileTok)
fileTok = fileTok->nextArgument(); fileTok = fileTok->nextArgument();
operation = Filepointer::UNIMPORTANT; operation = Filepointer::UNIMPORTANT;
} else if (!Token::Match(tok, "if|for|while|catch|switch") && _settings->library.functionpure.find(tok->str()) == _settings->library.functionpure.end()) { } else if (!Token::Match(tok, "if|for|while|catch|switch") && !_settings->library.isFunctionConst(tok->str(), true)) {
const Token* const end2 = tok->linkAt(1); const Token* const end2 = tok->linkAt(1);
if (scope->functionOf && scope->functionOf->isClassOrStruct() && !scope->function->isStatic() && ((tok->strAt(-1) != "::" && tok->strAt(-1) != ".") || tok->strAt(-2) == "this")) { if (scope->functionOf && scope->functionOf->isClassOrStruct() && !scope->function->isStatic() && ((tok->strAt(-1) != "::" && tok->strAt(-1) != ".") || tok->strAt(-2) == "this")) {
if (!tok->function() || (tok->function()->nestedIn && tok->function()->nestedIn->isClassOrStruct())) { if (!tok->function() || (tok->function()->nestedIn && tok->function()->nestedIn->isClassOrStruct())) {

View File

@ -460,8 +460,7 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
if (_tokenizer->IsScopeNoReturn(tok->tokAt(2), &unknown)) { if (_tokenizer->IsScopeNoReturn(tok->tokAt(2), &unknown)) {
if (!unknown) if (!unknown)
varInfo->clear(); varInfo->clear();
else if (_settings->library.leakignore.find(functionName) == _settings->library.leakignore.end() && else if (!_settings->library.isLeakIgnore(functionName) && !_settings->library.isUse(functionName))
_settings->library.use.find(functionName) == _settings->library.use.end())
varInfo->possibleUsageAll(functionName); varInfo->possibleUsageAll(functionName);
} }
} }
@ -526,8 +525,7 @@ void CheckLeakAutoVar::changeAllocStatus(VarInfo *varInfo, const VarInfo::AllocI
void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af) void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af)
{ {
// Ignore function call? // Ignore function call?
const bool ignore = bool(_settings->library.leakignore.find(tok->str()) != _settings->library.leakignore.end()); if (_settings->library.isLeakIgnore(tok->str()))
if (ignore)
return; return;
int argNr = 1; int argNr = 1;

View File

@ -494,7 +494,7 @@ static bool alwaysTrue(const Token *tok)
bool CheckMemoryLeakInFunction::test_white_list(const std::string &funcname, const Settings *settings, bool cpp) bool CheckMemoryLeakInFunction::test_white_list(const std::string &funcname, const Settings *settings, bool cpp)
{ {
return ((call_func_white_list.find(funcname)!=call_func_white_list.end()) || (settings->library.leakignore.find(funcname) != settings->library.leakignore.end()) || (cpp && funcname == "delete")); return ((call_func_white_list.find(funcname)!=call_func_white_list.end()) || settings->library.isLeakIgnore(funcname) || (cpp && funcname == "delete"));
} }
namespace { namespace {
@ -1318,7 +1318,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
parent = parent->astParent(); parent = parent->astParent();
if (parent && parent->astOperand1() && parent->astOperand1()->isName()) { if (parent && parent->astOperand1() && parent->astOperand1()->isName()) {
const std::string &functionName = parent->astOperand1()->str(); const std::string &functionName = parent->astOperand1()->str();
if (_settings->library.leakignore.find(functionName) != _settings->library.leakignore.end()) if (_settings->library.isLeakIgnore(functionName))
leakignore = true; leakignore = true;
} }
} }

View File

@ -574,7 +574,7 @@ void CheckOther::checkRedundantAssignment()
} }
// Ensure that LHS in assignments are the same // Ensure that LHS in assignments are the same
bool error = oldeq && eq->astOperand1() && isSameExpression(_tokenizer->isCPP(), true, eq->astOperand1(), oldeq->astOperand1(), _settings->library.functionpure); bool error = oldeq && eq->astOperand1() && isSameExpression(_tokenizer->isCPP(), true, eq->astOperand1(), oldeq->astOperand1(), _settings->library, true);
// Ensure that variable is not used on right side // Ensure that variable is not used on right side
std::stack<const Token *> tokens; std::stack<const Token *> tokens;
@ -635,7 +635,7 @@ void CheckOther::checkRedundantAssignment()
if (!writtenArgumentsEnd) // Indicates that we are in the first argument of strcpy/memcpy/... function if (!writtenArgumentsEnd) // Indicates that we are in the first argument of strcpy/memcpy/... function
memAssignments.erase(tok->varId()); memAssignments.erase(tok->varId());
} }
} else if (Token::Match(tok, "%name% (") && _settings->library.functionpure.find(tok->str()) == _settings->library.functionpure.end()) { // Function call. Global variables might be used. Reset their status } else if (Token::Match(tok, "%name% (") && !_settings->library.isFunctionConst(tok->str(), true)) { // Function call. Global variables might be used. Reset their status
const bool memfunc = Token::Match(tok, "memcpy|memmove|memset|strcpy|strncpy|sprintf|snprintf|strcat|strncat|wcscpy|wcsncpy|swprintf|wcscat|wcsncat"); const bool memfunc = Token::Match(tok, "memcpy|memmove|memset|strcpy|strncpy|sprintf|snprintf|strcat|strncat|wcscpy|wcsncpy|swprintf|wcscat|wcsncat");
if (tok->varId()) // operator() or function pointer if (tok->varId()) // operator() or function pointer
varAssignments.erase(tok->varId()); varAssignments.erase(tok->varId());
@ -1936,7 +1936,7 @@ void CheckOther::checkInvalidFree()
// If the previously-allocated variable is passed in to another function // If the previously-allocated variable is passed in to another function
// as a parameter, it might be modified, so we shouldn't report an error // as a parameter, it might be modified, so we shouldn't report an error
// if it is later used to free memory // if it is later used to free memory
else if (Token::Match(tok, "%name% (") && _settings->library.functionpure.find(tok->str()) == _settings->library.functionpure.end()) { else if (Token::Match(tok, "%name% (") && !_settings->library.isFunctionConst(tok->str(), true)) {
const Token* tok2 = Token::findmatch(tok->next(), "%var%", tok->linkAt(1)); const Token* tok2 = Token::findmatch(tok->next(), "%var%", tok->linkAt(1));
while (tok2 != nullptr) { while (tok2 != nullptr) {
allocatedVariables.erase(tok2->varId()); allocatedVariables.erase(tok2->varId());
@ -2001,7 +2001,6 @@ void CheckOther::checkDuplicateExpression()
std::list<Scope>::const_iterator scope; std::list<Scope>::const_iterator scope;
std::list<const Function*> constFunctions; std::list<const Function*> constFunctions;
const std::set<std::string> temp; // Can be used as dummy for isSameExpression()
getConstFunctions(symbolDatabase, constFunctions); getConstFunctions(symbolDatabase, constFunctions);
for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) { for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
@ -2013,7 +2012,7 @@ void CheckOther::checkDuplicateExpression()
if (tok->isOp() && tok->astOperand1() && !Token::Match(tok, "+|*|<<|>>|+=|*=|<<=|>>=")) { if (tok->isOp() && tok->astOperand1() && !Token::Match(tok, "+|*|<<|>>|+=|*=|<<=|>>=")) {
if (Token::Match(tok, "==|!=|-") && astIsFloat(tok->astOperand1(), true)) if (Token::Match(tok, "==|!=|-") && astIsFloat(tok->astOperand1(), true))
continue; continue;
if (isSameExpression(_tokenizer->isCPP(), true, tok->astOperand1(), tok->astOperand2(), _settings->library.functionpure)) { if (isSameExpression(_tokenizer->isCPP(), true, tok->astOperand1(), tok->astOperand2(), _settings->library, true)) {
if (isWithoutSideEffects(_tokenizer->isCPP(), tok->astOperand1())) { if (isWithoutSideEffects(_tokenizer->isCPP(), tok->astOperand1())) {
const bool assignment = tok->str() == "="; const bool assignment = tok->str() == "=";
if (assignment && warningEnabled) if (assignment && warningEnabled)
@ -2033,25 +2032,25 @@ void CheckOther::checkDuplicateExpression()
} }
} }
} else if (!Token::Match(tok, "[-/%]")) { // These operators are not associative } else if (!Token::Match(tok, "[-/%]")) { // These operators are not associative
if (styleEnabled && tok->astOperand2() && tok->str() == tok->astOperand1()->str() && isSameExpression(_tokenizer->isCPP(), true, tok->astOperand2(), tok->astOperand1()->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer->isCPP(), tok->astOperand2())) if (styleEnabled && tok->astOperand2() && tok->str() == tok->astOperand1()->str() && isSameExpression(_tokenizer->isCPP(), true, tok->astOperand2(), tok->astOperand1()->astOperand2(), _settings->library, true) && isWithoutSideEffects(_tokenizer->isCPP(), tok->astOperand2()))
duplicateExpressionError(tok->astOperand2(), tok->astOperand2(), tok->str()); duplicateExpressionError(tok->astOperand2(), tok->astOperand2(), tok->str());
else if (tok->astOperand2()) { else if (tok->astOperand2()) {
const Token *ast1 = tok->astOperand1(); const Token *ast1 = tok->astOperand1();
while (ast1 && tok->str() == ast1->str()) { while (ast1 && tok->str() == ast1->str()) {
if (isSameExpression(_tokenizer->isCPP(), true, ast1->astOperand1(), tok->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer->isCPP(), ast1->astOperand1())) if (isSameExpression(_tokenizer->isCPP(), true, ast1->astOperand1(), tok->astOperand2(), _settings->library, true) && isWithoutSideEffects(_tokenizer->isCPP(), ast1->astOperand1()))
// TODO: warn if variables are unchanged. See #5683 // TODO: warn if variables are unchanged. See #5683
// Probably the message should be changed to 'duplicate expressions X in condition or something like that'. // Probably the message should be changed to 'duplicate expressions X in condition or something like that'.
;//duplicateExpressionError(ast1->astOperand1(), tok->astOperand2(), tok->str()); ;//duplicateExpressionError(ast1->astOperand1(), tok->astOperand2(), tok->str());
else if (styleEnabled && isSameExpression(_tokenizer->isCPP(), true, ast1->astOperand2(), tok->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer->isCPP(), ast1->astOperand2())) else if (styleEnabled && isSameExpression(_tokenizer->isCPP(), true, ast1->astOperand2(), tok->astOperand2(), _settings->library, true) && isWithoutSideEffects(_tokenizer->isCPP(), ast1->astOperand2()))
duplicateExpressionError(ast1->astOperand2(), tok->astOperand2(), tok->str()); duplicateExpressionError(ast1->astOperand2(), tok->astOperand2(), tok->str());
if (!isConstExpression(ast1->astOperand2(), _settings->library.functionpure)) if (!isConstExpression(ast1->astOperand2(), _settings->library, true))
break; break;
ast1 = ast1->astOperand1(); ast1 = ast1->astOperand1();
} }
} }
} }
} else if (styleEnabled && tok->astOperand1() && tok->astOperand2() && tok->str() == ":" && tok->astParent() && tok->astParent()->str() == "?") { } else if (styleEnabled && tok->astOperand1() && tok->astOperand2() && tok->str() == ":" && tok->astParent() && tok->astParent()->str() == "?") {
if (isSameExpression(_tokenizer->isCPP(), true, tok->astOperand1(), tok->astOperand2(), temp)) if (isSameExpression(_tokenizer->isCPP(), true, tok->astOperand1(), tok->astOperand2(), _settings->library, false))
duplicateExpressionTernaryError(tok); duplicateExpressionTernaryError(tok);
} }
} }
@ -2655,9 +2654,9 @@ void CheckOther::checkEvaluationOrder()
if (tok2 == tok && if (tok2 == tok &&
tok->str() == "=" && tok->str() == "=" &&
parent->str() == "=" && parent->str() == "=" &&
isSameExpression(_tokenizer->isCPP(), false, tok->astOperand1(), parent->astOperand1(), _settings->library.functionpure)) { isSameExpression(_tokenizer->isCPP(), false, tok->astOperand1(), parent->astOperand1(), _settings->library, true)) {
if (_settings->isEnabled("warning") && if (_settings->isEnabled("warning") &&
isSameExpression(_tokenizer->isCPP(), true, tok->astOperand1(), parent->astOperand1(), _settings->library.functionpure)) isSameExpression(_tokenizer->isCPP(), true, tok->astOperand1(), parent->astOperand1(), _settings->library, true))
selfAssignmentError(parent, tok->astOperand1()->expressionString()); selfAssignmentError(parent, tok->astOperand1()->expressionString());
break; break;
} }
@ -2677,7 +2676,7 @@ void CheckOther::checkEvaluationOrder()
continue; // don't care about sizeof usage continue; // don't care about sizeof usage
tokens.push(tok3->astOperand1()); tokens.push(tok3->astOperand1());
tokens.push(tok3->astOperand2()); tokens.push(tok3->astOperand2());
if (isSameExpression(_tokenizer->isCPP(), false, tok->astOperand1(), tok3, _settings->library.functionpure)) { if (isSameExpression(_tokenizer->isCPP(), false, tok->astOperand1(), tok3, _settings->library, true)) {
foundError = true; foundError = true;
} }
} }

View File

@ -888,7 +888,7 @@ bool CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc al
break; break;
} }
if (alloc != NO_ALLOC && parent->str() == "(") { if (alloc != NO_ALLOC && parent->str() == "(") {
if (_settings->library.functionpure.find(parent->strAt(-1)) == _settings->library.functionpure.end()) { if (!_settings->library.isFunctionConst(parent->strAt(-1), true)) {
assignment = true; assignment = true;
break; break;
} }

View File

@ -187,7 +187,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
temp.arg = 1; temp.arg = 1;
_dealloc[memorynode->GetText()] = temp; _dealloc[memorynode->GetText()] = temp;
} else if (memorynodename == "use") } else if (memorynodename == "use")
use.insert(memorynode->GetText()); functions[memorynode->GetText()].use = true;
else else
unknown_elements.insert(memorynodename); unknown_elements.insert(memorynodename);
} }
@ -537,14 +537,14 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
if (functionnodename == "noreturn") if (functionnodename == "noreturn")
_noreturn[name] = (strcmp(functionnode->GetText(), "true") == 0); _noreturn[name] = (strcmp(functionnode->GetText(), "true") == 0);
else if (functionnodename == "pure") else if (functionnodename == "pure")
functionpure.insert(name); functions[name].ispure = true;
else if (functionnodename == "const") { else if (functionnodename == "const") {
functionconst.insert(name); functions[name].ispure = true;
functionpure.insert(name); // a constant function is pure functions[name].isconst = true; // a constant function is pure
} else if (functionnodename == "leak-ignore") } else if (functionnodename == "leak-ignore")
leakignore.insert(name); functions[name].leakignore = true;
else if (functionnodename == "use-retval") else if (functionnodename == "use-retval")
_useretval.insert(name); functions[name].useretval = true;
else if (functionnodename == "returnValue") { else if (functionnodename == "returnValue") {
if (const char *expr = functionnode->GetText()) if (const char *expr = functionnode->GetText())
_returnValue[name] = expr; _returnValue[name] = expr;
@ -558,7 +558,7 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
return Error(MISSING_ATTRIBUTE, "nr"); return Error(MISSING_ATTRIBUTE, "nr");
const bool bAnyArg = strcmp(argNrString, "any")==0; const bool bAnyArg = strcmp(argNrString, "any")==0;
const int nr = bAnyArg ? -1 : std::atoi(argNrString); const int nr = bAnyArg ? -1 : std::atoi(argNrString);
ArgumentChecks &ac = argumentChecks[name][nr]; ArgumentChecks &ac = functions[name].argumentChecks[nr];
ac.optional = functionnode->Attribute("default") != nullptr; ac.optional = functionnode->Attribute("default") != nullptr;
for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) { for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) {
const std::string argnodename = argnode->Name(); const std::string argnodename = argnode->Name();
@ -633,19 +633,25 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
} }
else if (argnodename == "iterator") { else if (argnodename == "iterator") {
ac.iteratorInfo.setType(argnode->Attribute("type")); ac.iteratorInfo.it = true;
ac.iteratorInfo.setContainer(argnode->Attribute("container")); const char* str = argnode->Attribute("type");
ac.iteratorInfo.first = str ? (std::strcmp(str, "first") == 0) : false;
ac.iteratorInfo.last = str ? (std::strcmp(str, "last") == 0) : false;
str = argnode->Attribute("container");
ac.iteratorInfo.container = str ? std::atoi(str) : 0;
} }
else else
unknown_elements.insert(argnodename); unknown_elements.insert(argnodename);
} }
} else if (functionnodename == "ignorefunction") { } else if (functionnodename == "ignorefunction") {
_ignorefunction.insert(name); functions[name].ignore = true;
} else if (functionnodename == "formatstr") { } else if (functionnodename == "formatstr") {
functions[name].formatstr = true;
const tinyxml2::XMLAttribute* scan = functionnode->FindAttribute("scan"); const tinyxml2::XMLAttribute* scan = functionnode->FindAttribute("scan");
const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute("secure"); const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute("secure");
_formatstr[name] = std::make_pair(scan && scan->BoolValue(), secure && secure->BoolValue()); functions[name].formatstr_scan = scan && scan->BoolValue();
functions[name].formatstr_secure = secure && secure->BoolValue();
} else if (functionnodename == "warn") { } else if (functionnodename == "warn") {
WarnInfo wi; WarnInfo wi;
const char* const severity = functionnode->Attribute("severity"); const char* const severity = functionnode->Attribute("severity");
@ -788,8 +794,8 @@ bool Library::isnullargbad(const Token *ftok, int argnr) const
if (!arg) { if (!arg) {
// scan format string argument should not be null // scan format string argument should not be null
const std::string funcname = getFunctionName(ftok); const std::string funcname = getFunctionName(ftok);
std::map<std::string, std::pair<bool, bool> >::const_iterator it = _formatstr.find(funcname); std::map<std::string, Function>::const_iterator it = functions.find(funcname);
if (it != _formatstr.end() && it->second.first) if (it != functions.cend() && it->second.formatstr && it->second.formatstr_scan)
return true; return true;
} }
return arg && arg->notnull; return arg && arg->notnull;
@ -801,8 +807,8 @@ bool Library::isuninitargbad(const Token *ftok, int argnr) const
if (!arg) { if (!arg) {
// non-scan format string argument should not be uninitialized // non-scan format string argument should not be uninitialized
const std::string funcname = getFunctionName(ftok); const std::string funcname = getFunctionName(ftok);
std::map<std::string, std::pair<bool, bool> >::const_iterator it = _formatstr.find(funcname); std::map<std::string, Function>::const_iterator it = functions.find(funcname);
if (it != _formatstr.end() && !it->second.first) if (it != functions.cend() && it->second.formatstr && !it->second.formatstr_scan)
return true; return true;
} }
return arg && arg->notuninit; return arg && arg->notuninit;
@ -813,14 +819,14 @@ bool Library::isuninitargbad(const Token *ftok, int argnr) const
const Library::AllocFunc* Library::alloc(const Token *tok) const const Library::AllocFunc* Library::alloc(const Token *tok) const
{ {
const std::string funcname = getFunctionName(tok); const std::string funcname = getFunctionName(tok);
return isNotLibraryFunction(tok) && argumentChecks.find(funcname) != argumentChecks.end() ? 0 : getAllocDealloc(_alloc, funcname); return isNotLibraryFunction(tok) && functions.find(funcname) != functions.end() ? 0 : getAllocDealloc(_alloc, funcname);
} }
/** get deallocation info for function */ /** get deallocation info for function */
const Library::AllocFunc* Library::dealloc(const Token *tok) const const Library::AllocFunc* Library::dealloc(const Token *tok) const
{ {
const std::string funcname = getFunctionName(tok); const std::string funcname = getFunctionName(tok);
return isNotLibraryFunction(tok) && argumentChecks.find(funcname) != argumentChecks.end() ? 0 : getAllocDealloc(_dealloc, funcname); return isNotLibraryFunction(tok) && functions.find(funcname) != functions.end() ? 0 : getAllocDealloc(_dealloc, funcname);
} }
/** get allocation id for function */ /** get allocation id for function */
@ -842,15 +848,14 @@ const Library::ArgumentChecks * Library::getarg(const Token *ftok, int argnr) co
{ {
if (isNotLibraryFunction(ftok)) if (isNotLibraryFunction(ftok))
return nullptr; return nullptr;
std::map<std::string, std::map<int, ArgumentChecks> >::const_iterator it1; std::map<std::string, Function>::const_iterator it1 = functions.find(getFunctionName(ftok));
it1 = argumentChecks.find(getFunctionName(ftok)); if (it1 == functions.cend())
if (it1 == argumentChecks.end())
return nullptr; return nullptr;
const std::map<int,ArgumentChecks>::const_iterator it2 = it1->second.find(argnr); const std::map<int,ArgumentChecks>::const_iterator it2 = it1->second.argumentChecks.find(argnr);
if (it2 != it1->second.end()) if (it2 != it1->second.argumentChecks.cend())
return &it2->second; return &it2->second;
const std::map<int,ArgumentChecks>::const_iterator it3 = it1->second.find(-1); const std::map<int,ArgumentChecks>::const_iterator it3 = it1->second.argumentChecks.find(-1);
if (it3 != it1->second.end()) if (it3 != it1->second.argumentChecks.cend())
return &it3->second; return &it3->second;
return nullptr; return nullptr;
} }
@ -926,12 +931,12 @@ bool Library::isNotLibraryFunction(const Token *ftok) const
bool Library::matchArguments(const Token *ftok, const std::string &functionName) const bool Library::matchArguments(const Token *ftok, const std::string &functionName) const
{ {
int callargs = numberOfArguments(ftok); int callargs = numberOfArguments(ftok);
const std::map<std::string, std::map<int, ArgumentChecks> >::const_iterator it = argumentChecks.find(functionName); const std::map<std::string, Function>::const_iterator it = functions.find(functionName);
if (it == argumentChecks.end()) if (it == functions.cend())
return (callargs == 0); return (callargs == 0);
int args = 0; int args = 0;
int firstOptionalArg = -1; int firstOptionalArg = -1;
for (std::map<int, ArgumentChecks>::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) { for (std::map<int, ArgumentChecks>::const_iterator it2 = it->second.argumentChecks.cbegin(); it2 != it->second.argumentChecks.cend(); ++it2) {
if (it2->first > args) if (it2->first > args)
args = it2->first; args = it2->first;
if (it2->second.optional && (firstOptionalArg == -1 || firstOptionalArg > it2->first)) if (it2->second.optional && (firstOptionalArg == -1 || firstOptionalArg > it2->first))
@ -955,13 +960,18 @@ const Library::WarnInfo* Library::getWarnInfo(const Token* ftok) const
bool Library::formatstr_function(const Token* ftok) const bool Library::formatstr_function(const Token* ftok) const
{ {
return (!isNotLibraryFunction(ftok) && if (isNotLibraryFunction(ftok))
_formatstr.find(getFunctionName(ftok)) != _formatstr.cend()); return false;
std::map<std::string, Library::Function>::const_iterator it = functions.find(getFunctionName(ftok));
if (it != functions.cend())
return it->second.formatstr;
return false;
} }
int Library::formatstr_argno(const Token* ftok) const int Library::formatstr_argno(const Token* ftok) const
{ {
const std::map<int, Library::ArgumentChecks>& argumentChecksFunc = argumentChecks.at(getFunctionName(ftok)); const std::map<int, Library::ArgumentChecks>& argumentChecksFunc = functions.at(getFunctionName(ftok)).argumentChecks;
for (std::map<int, Library::ArgumentChecks>::const_iterator i = argumentChecksFunc.cbegin(); i != argumentChecksFunc.cend(); ++i) { for (std::map<int, Library::ArgumentChecks>::const_iterator i = argumentChecksFunc.cbegin(); i != argumentChecksFunc.cend(); ++i) {
if (i->second.formatstr) { if (i->second.formatstr) {
return i->first - 1; return i->first - 1;
@ -972,18 +982,22 @@ int Library::formatstr_argno(const Token* ftok) const
bool Library::formatstr_scan(const Token* ftok) const bool Library::formatstr_scan(const Token* ftok) const
{ {
return _formatstr.at(getFunctionName(ftok)).first; return functions.at(getFunctionName(ftok)).formatstr_scan;
} }
bool Library::formatstr_secure(const Token* ftok) const bool Library::formatstr_secure(const Token* ftok) const
{ {
return _formatstr.at(getFunctionName(ftok)).second; return functions.at(getFunctionName(ftok)).formatstr_secure;
} }
bool Library::isUseRetVal(const Token* ftok) const bool Library::isUseRetVal(const Token* ftok) const
{ {
return (!isNotLibraryFunction(ftok) && if (isNotLibraryFunction(ftok))
_useretval.find(getFunctionName(ftok)) != _useretval.end()); return false;
std::map<std::string, Library::Function>::const_iterator it = functions.find(getFunctionName(ftok));
if (it != functions.cend())
return it->second.useretval;
return false;
} }
const std::string& Library::returnValue(const Token *ftok) const const std::string& Library::returnValue(const Token *ftok) const
@ -1010,6 +1024,47 @@ int Library::returnValueContainer(const Token *ftok) const
return it != _returnValueContainer.end() ? it->second : -1; return it != _returnValueContainer.end() ? it->second : -1;
} }
bool Library::hasminsize(const std::string &functionName) const
{
std::map<std::string, Function>::const_iterator it1 = functions.find(functionName);
if (it1 == functions.cend())
return false;
for (std::map<int, ArgumentChecks>::const_iterator it2 = it1->second.argumentChecks.cbegin(); it2 != it1->second.argumentChecks.cend(); ++it2) {
if (!it2->second.minsizes.empty())
return true;
}
return false;
}
bool Library::ignorefunction(const std::string& functionName) const
{
std::map<std::string, Library::Function>::const_iterator it = functions.find(functionName);
if (it != functions.cend())
return it->second.ignore;
return false;
}
bool Library::isUse(const std::string& functionName) const
{
std::map<std::string, Library::Function>::const_iterator it = functions.find(functionName);
if (it != functions.cend())
return it->second.use;
return false;
}
bool Library::isLeakIgnore(const std::string& functionName) const
{
std::map<std::string, Library::Function>::const_iterator it = functions.find(functionName);
if (it != functions.cend())
return it->second.leakignore;
return false;
}
bool Library::isFunctionConst(const std::string& functionName, bool pure) const
{
std::map<std::string, Library::Function>::const_iterator it = functions.find(functionName);
if (it != functions.cend())
return pure ? it->second.ispure : it->second.isconst;
return false;
}
bool Library::isnoreturn(const Token *ftok) const bool Library::isnoreturn(const Token *ftok) const
{ {
if (ftok->function() && ftok->function()->isAttributeNoreturn()) if (ftok->function() && ftok->function()->isAttributeNoreturn())

View File

@ -31,7 +31,6 @@
#include <string> #include <string>
#include <list> #include <list>
#include <vector> #include <vector>
#include <cstring>
namespace tinyxml2 { namespace tinyxml2 {
class XMLDocument; class XMLDocument;
@ -54,9 +53,10 @@ public:
class Error { class Error {
public: public:
Error() : errorcode(OK) , reason("") {} Error() : errorcode(OK) {}
explicit Error(ErrorCode e) : errorcode(e) , reason("") {} explicit Error(ErrorCode e) : errorcode(e) {}
Error(ErrorCode e, const std::string &r) : errorcode(e), reason(r) {} template<typename T>
Error(ErrorCode e, T&& r) : errorcode(e), reason(r) {}
ErrorCode errorcode; ErrorCode errorcode;
std::string reason; std::string reason;
}; };
@ -139,18 +139,10 @@ public:
} }
bool formatstr_function(const Token* ftok) const; bool formatstr_function(const Token* ftok) const;
int formatstr_argno(const Token* ftok) const; int formatstr_argno(const Token* ftok) const;
bool formatstr_scan(const Token* ftok) const; bool formatstr_scan(const Token* ftok) const;
bool formatstr_secure(const Token* ftok) const; bool formatstr_secure(const Token* ftok) const;
std::set<std::string> use;
std::set<std::string> leakignore;
std::set<std::string> functionconst;
std::set<std::string> functionpure;
struct WarnInfo { struct WarnInfo {
std::string message; std::string message;
Standards standards; Standards standards;
@ -245,15 +237,6 @@ public:
class IteratorInfo { class IteratorInfo {
public: public:
IteratorInfo() : it(false), container(0), first(false), last(false) {} IteratorInfo() : it(false), container(0), first(false), last(false) {}
void setContainer(const char *str) {
it = true;
container = str ? std::atoi(str) : 0;
}
void setType(const char *str) {
it = true;
first = str ? (std::strcmp(str,"first") == 0) : false;
last = str ? (std::strcmp(str,"last") == 0) : false;
}
bool it; bool it;
int container; int container;
@ -264,7 +247,7 @@ public:
class MinSize { class MinSize {
public: public:
enum Type {NONE,STRLEN,ARGVALUE,SIZEOF,MUL}; enum Type { NONE, STRLEN, ARGVALUE, SIZEOF, MUL };
MinSize(Type t, int a) : type(t), arg(a), arg2(0) {} MinSize(Type t, int a) : type(t), arg(a), arg2(0) {}
Type type; Type type;
int arg; int arg;
@ -273,8 +256,25 @@ public:
std::list<MinSize> minsizes; std::list<MinSize> minsizes;
}; };
// function name, argument nr => argument data
std::map<std::string, std::map<int, ArgumentChecks> > argumentChecks; struct Function {
std::map<int, ArgumentChecks> argumentChecks; // argument nr => argument data
bool use;
bool leakignore;
bool isconst;
bool ispure;
bool useretval;
bool ignore; // ignore functions/macros from a library (gtk, qt etc)
bool formatstr;
bool formatstr_scan;
bool formatstr_secure;
Function() : use(false), leakignore(false), isconst(false), ispure(false), useretval(false), ignore(false), formatstr(false), formatstr_scan(false), formatstr_secure(false) {}
};
std::map<std::string, Function> functions;
bool isUse(const std::string& functionName) const;
bool isLeakIgnore(const std::string& functionName) const;
bool isFunctionConst(const std::string& functionName, bool pure) const;
bool isboolargbad(const Token *ftok, int argnr) const { bool isboolargbad(const Token *ftok, int argnr) const {
const ArgumentChecks *arg = getarg(ftok, argnr); const ArgumentChecks *arg = getarg(ftok, argnr);
@ -306,18 +306,7 @@ public:
return arg && arg->iteratorInfo.it ? &arg->iteratorInfo : nullptr; return arg && arg->iteratorInfo.it ? &arg->iteratorInfo : nullptr;
} }
bool hasminsize(const std::string &functionName) const { bool hasminsize(const std::string &functionName) const;
std::map<std::string, std::map<int, ArgumentChecks> >::const_iterator it1;
it1 = argumentChecks.find(functionName);
if (it1 == argumentChecks.end())
return false;
std::map<int,ArgumentChecks>::const_iterator it2;
for (it2 = it1->second.begin(); it2 != it1->second.end(); ++it2) {
if (!it2->second.minsizes.empty())
return true;
}
return false;
}
const std::list<ArgumentChecks::MinSize> *argminsizes(const Token *ftok, int argnr) const { const std::list<ArgumentChecks::MinSize> *argminsizes(const Token *ftok, int argnr) const {
const ArgumentChecks *arg = getarg(ftok, argnr); const ArgumentChecks *arg = getarg(ftok, argnr);
@ -334,9 +323,7 @@ public:
bool reportErrors(const std::string &path) const; bool reportErrors(const std::string &path) const;
bool ignorefunction(const std::string &function) const { bool ignorefunction(const std::string &function) const;
return (_ignorefunction.find(function) != _ignorefunction.end());
}
bool isexecutableblock(const std::string &file, const std::string &token) const; bool isexecutableblock(const std::string &file, const std::string &token) const;
@ -401,13 +388,13 @@ public:
, _const_ptr(false) { , _const_ptr(false) {
} }
bool operator == (const PlatformType & type) const { bool operator == (const PlatformType & type) const {
return (_type == type._type && return (_signed == type._signed &&
_signed == type._signed &&
_unsigned == type._unsigned && _unsigned == type._unsigned &&
_long == type._long && _long == type._long &&
_pointer == type._pointer && _pointer == type._pointer &&
_ptr_ptr == type._ptr_ptr && _ptr_ptr == type._ptr_ptr &&
_const_ptr == type._const_ptr); _const_ptr == type._const_ptr &&
_type == type._type);
} }
bool operator != (const PlatformType & type) const { bool operator != (const PlatformType & type) const {
return !(*this == type); return !(*this == type);
@ -431,16 +418,13 @@ public:
const PlatformType *platform_type(const std::string &name, const std::string & platform) const { const PlatformType *platform_type(const std::string &name, const std::string & platform) const {
const std::map<std::string, Platform>::const_iterator it = platforms.find(platform); const std::map<std::string, Platform>::const_iterator it = platforms.find(platform);
if (it != platforms.end()) { if (it != platforms.end()) {
const PlatformType * const type = it->second.platform_type(name); const PlatformType * const type = it->second.platform_type(name);
if (type) if (type)
return type; return type;
} }
const std::map<std::string, PlatformType>::const_iterator it2 = platform_types.find(name); const std::map<std::string, PlatformType>::const_iterator it2 = platform_types.find(name);
return (it2 != platform_types.end()) ? &(it2->second) : nullptr; return (it2 != platform_types.end()) ? &(it2->second) : nullptr;
} }
@ -504,7 +488,6 @@ private:
}; };
int allocid; int allocid;
std::set<std::string> _files; std::set<std::string> _files;
std::set<std::string> _useretval;
std::map<std::string, AllocFunc> _alloc; // allocation functions std::map<std::string, AllocFunc> _alloc; // allocation functions
std::map<std::string, AllocFunc> _dealloc; // deallocation functions std::map<std::string, AllocFunc> _dealloc; // deallocation functions
std::set<std::string> _functions; std::set<std::string> _functions;
@ -512,7 +495,6 @@ private:
std::map<std::string, std::string> _returnValue; std::map<std::string, std::string> _returnValue;
std::map<std::string, std::string> _returnValueType; std::map<std::string, std::string> _returnValueType;
std::map<std::string, int> _returnValueContainer; std::map<std::string, int> _returnValueContainer;
std::set<std::string> _ignorefunction; // ignore functions/macros from a library (gtk, qt etc)
std::map<std::string, bool> _reporterrors; std::map<std::string, bool> _reporterrors;
std::map<std::string, bool> _processAfterCode; std::map<std::string, bool> _processAfterCode;
std::set<std::string> _markupExtensions; // file extensions of markup files std::set<std::string> _markupExtensions; // file extensions of markup files
@ -520,8 +502,7 @@ private:
std::map<std::string, CodeBlock> _executableblocks; // keywords for blocks of executable code std::map<std::string, CodeBlock> _executableblocks; // keywords for blocks of executable code
std::map<std::string, ExportedFunctions> _exporters; // keywords that export variables/functions to libraries (meta-code/macros) std::map<std::string, ExportedFunctions> _exporters; // keywords that export variables/functions to libraries (meta-code/macros)
std::map<std::string, std::set<std::string> > _importers; // keywords that import variables/functions std::map<std::string, std::set<std::string> > _importers; // keywords that import variables/functions
std::map<std::string,int> _reflection; // invocation of reflection std::map<std::string, int> _reflection; // invocation of reflection
std::map<std::string, std::pair<bool, bool> > _formatstr; // Parameters for format string checking
std::map<std::string, struct PodType> podtypes; // pod types std::map<std::string, struct PodType> podtypes; // pod types
std::map<std::string, PlatformType> platform_types; // platform independent typedefs std::map<std::string, PlatformType> platform_types; // platform independent typedefs
std::map<std::string, Platform> platforms; // platform dependent typedefs std::map<std::string, Platform> platforms; // platform dependent typedefs

View File

@ -8420,9 +8420,9 @@ void Tokenizer::simplifyAttribute()
{ {
for (Token *tok = list.front(); tok; tok = tok->next()) { for (Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "%type% (") && !_settings->library.isNotLibraryFunction(tok)) { if (Token::Match(tok, "%type% (") && !_settings->library.isNotLibraryFunction(tok)) {
if (_settings->library.functionpure.find(tok->str()) != _settings->library.functionpure.end()) if (_settings->library.isFunctionConst(tok->str(), true))
tok->isAttributePure(true); tok->isAttributePure(true);
if (_settings->library.functionconst.find(tok->str()) != _settings->library.functionconst.end()) if (_settings->library.isFunctionConst(tok->str(), false))
tok->isAttributeConst(true); tok->isAttributeConst(true);
} }
while (Token::Match(tok, "__attribute__|__attribute (") && tok->next()->link() && tok->next()->link()->next()) { while (Token::Match(tok, "__attribute__|__attribute (") && tok->next()->link() && tok->next()->link()->next()) {

View File

@ -856,7 +856,7 @@ static void valueFlowOppositeCondition(SymbolDatabase *symboldatabase, const Set
const Token *cond2 = tok2->tokAt(4)->astOperand2(); const Token *cond2 = tok2->tokAt(4)->astOperand2();
if (!cond2 || !cond2->isComparisonOp()) if (!cond2 || !cond2->isComparisonOp())
continue; continue;
if (isOppositeCond(true, cpp, cond1, cond2, settings->library.functionpure)) { if (isOppositeCond(true, cpp, cond1, cond2, settings->library, true)) {
ValueFlow::Value value(1); ValueFlow::Value value(1);
value.setKnown(); value.setKnown();
setTokenValue(const_cast<Token*>(cond2), value, settings); setTokenValue(const_cast<Token*>(cond2), value, settings);

View File

@ -66,9 +66,7 @@ private:
Library library; Library library;
readLibrary(library, xmldata); readLibrary(library, xmldata);
ASSERT(library.use.empty()); ASSERT(library.functions.empty());
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
} }
void function() const { void function() const {
@ -86,9 +84,7 @@ private:
Library library; Library library;
readLibrary(library, xmldata); readLibrary(library, xmldata);
ASSERT(library.use.empty()); ASSERT(library.functions.empty());
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
ASSERT(library.isnotnoreturn(tokenList.front())); ASSERT(library.isnotnoreturn(tokenList.front()));
} }
@ -222,13 +218,13 @@ private:
Library library; Library library;
readLibrary(library, xmldata); readLibrary(library, xmldata);
ASSERT_EQUALS(true, library.argumentChecks["foo"][1].notuninit); ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[1].notuninit);
ASSERT_EQUALS(true, library.argumentChecks["foo"][2].notnull); ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[2].notnull);
ASSERT_EQUALS(true, library.argumentChecks["foo"][3].formatstr); ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[3].formatstr);
ASSERT_EQUALS(true, library.argumentChecks["foo"][4].strz); ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[4].strz);
ASSERT_EQUALS(false, library.argumentChecks["foo"][4].optional); ASSERT_EQUALS(false, library.functions["foo"].argumentChecks[4].optional);
ASSERT_EQUALS(true, library.argumentChecks["foo"][5].notbool); ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[5].notbool);
ASSERT_EQUALS(true, library.argumentChecks["foo"][5].optional); ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[5].optional);
} }
void function_arg_any() const { void function_arg_any() const {
@ -241,7 +237,7 @@ private:
Library library; Library library;
readLibrary(library, xmldata); readLibrary(library, xmldata);
ASSERT_EQUALS(true, library.argumentChecks["foo"][-1].notuninit); ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[-1].notuninit);
} }
void function_arg_valid() const { void function_arg_valid() const {
@ -346,9 +342,7 @@ private:
Library library; Library library;
readLibrary(library, xmldata); readLibrary(library, xmldata);
ASSERT(library.use.empty()); ASSERT(library.functions.empty());
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
{ {
TokenList tokenList(nullptr); TokenList tokenList(nullptr);
@ -375,9 +369,7 @@ private:
Library library; Library library;
readLibrary(library, xmldata); readLibrary(library, xmldata);
ASSERT(library.use.empty()); ASSERT(library.functions.empty());
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
{ {
Settings settings; Settings settings;
@ -471,9 +463,7 @@ private:
Library library; Library library;
readLibrary(library, xmldata); readLibrary(library, xmldata);
ASSERT(library.use.empty()); ASSERT(library.functions.empty());
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
ASSERT(Library::ismemory(library.alloc("CreateX"))); ASSERT(Library::ismemory(library.alloc("CreateX")));
ASSERT_EQUALS(library.allocId("CreateX"), library.deallocId("DeleteX")); ASSERT_EQUALS(library.allocId("CreateX"), library.deallocId("DeleteX"));
@ -516,9 +506,7 @@ private:
Library library; Library library;
readLibrary(library, xmldata); readLibrary(library, xmldata);
ASSERT(library.use.empty()); ASSERT(library.functions.empty());
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
const Library::AllocFunc* af = library.alloc("CreateX"); const Library::AllocFunc* af = library.alloc("CreateX");
ASSERT(af && af->arg == 5); ASSERT(af && af->arg == 5);
@ -539,9 +527,7 @@ private:
Library library; Library library;
readLibrary(library, xmldata); readLibrary(library, xmldata);
ASSERT(library.use.empty()); ASSERT(library.functions.empty());
ASSERT(library.leakignore.empty());
ASSERT(library.argumentChecks.empty());
ASSERT(Library::isresource(library.allocId("CreateX"))); ASSERT(Library::isresource(library.allocId("CreateX")));
ASSERT_EQUALS(library.allocId("CreateX"), library.deallocId("DeleteX")); ASSERT_EQUALS(library.allocId("CreateX"), library.deallocId("DeleteX"));

View File

@ -2254,9 +2254,9 @@ private:
{ {
Library library; Library library;
Library::ArgumentChecks arg; Library::ArgumentChecks arg;
library.argumentChecks["x"][1] = arg; library.functions["x"].argumentChecks[1] = arg;
library.argumentChecks["x"][2] = arg; library.functions["x"].argumentChecks[2] = arg;
library.argumentChecks["x"][3] = arg; library.functions["x"].argumentChecks[3] = arg;
std::list<const Token *> null, uninit; std::list<const Token *> null, uninit;
CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U); CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U);
@ -2269,10 +2269,10 @@ private:
{ {
Library library; Library library;
Library::ArgumentChecks arg; Library::ArgumentChecks arg;
library.argumentChecks["x"][1] = arg; library.functions["x"].argumentChecks[1] = arg;
library.argumentChecks["x"][2] = arg; library.functions["x"].argumentChecks[2] = arg;
library.argumentChecks["x"][3] = arg; library.functions["x"].argumentChecks[3] = arg;
library.argumentChecks["x"][1].notnull = true; library.functions["x"].argumentChecks[1].notnull = true;
std::list<const Token *> null,uninit; std::list<const Token *> null,uninit;
CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U); CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U);
@ -2286,10 +2286,10 @@ private:
{ {
Library library; Library library;
Library::ArgumentChecks arg; Library::ArgumentChecks arg;
library.argumentChecks["x"][1] = arg; library.functions["x"].argumentChecks[1] = arg;
library.argumentChecks["x"][2] = arg; library.functions["x"].argumentChecks[2] = arg;
library.argumentChecks["x"][3] = arg; library.functions["x"].argumentChecks[3] = arg;
library.argumentChecks["x"][2].notuninit = true; library.functions["x"].argumentChecks[2].notuninit = true;
std::list<const Token *> null,uninit; std::list<const Token *> null,uninit;
CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U); CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U);
@ -2303,10 +2303,10 @@ private:
{ {
Library library; Library library;
Library::ArgumentChecks arg; Library::ArgumentChecks arg;
library.argumentChecks["x"][1] = arg; library.functions["x"].argumentChecks[1] = arg;
library.argumentChecks["x"][2] = arg; library.functions["x"].argumentChecks[2] = arg;
library.argumentChecks["x"][3] = arg; library.functions["x"].argumentChecks[3] = arg;
library.argumentChecks["x"][3].notuninit = true; library.functions["x"].argumentChecks[3].notuninit = true;
std::list<const Token *> null,uninit; std::list<const Token *> null,uninit;
CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U); CheckNullPointer::parseFunctionCall(*xtok, null, &library, 0U);

View File

@ -2291,7 +2291,7 @@ private:
Settings settings; Settings settings;
settings.library.setnoreturn("exit", true); settings.library.setnoreturn("exit", true);
settings.library.argumentChecks["exit"][1] = Library::ArgumentChecks(); settings.library.functions["exit"].argumentChecks[1] = Library::ArgumentChecks();
check("void foo() {\n" check("void foo() {\n"
" exit(0);\n" " exit(0);\n"
" break;\n" " break;\n"