Fixed #7668 (ValueFlow: return value from abs)
This commit is contained in:
parent
0e9bf9f0c6
commit
fae4a4dacf
|
@ -10,6 +10,7 @@
|
|||
<pure/>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<returnValue>arg1>0?arg1:-arg1</returnValue>
|
||||
<arg nr="1">
|
||||
<not-uninit/>
|
||||
<not-bool/>
|
||||
|
@ -1584,6 +1585,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
|||
<pure/>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<returnValue>arg1>='0' && arg1<='9'</returnValue>
|
||||
<arg nr="1">
|
||||
<not-uninit/>
|
||||
<valid>0:255</valid>
|
||||
|
@ -3034,6 +3036,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
|
|||
<pure/>
|
||||
<noreturn>false</noreturn>
|
||||
<leak-ignore/>
|
||||
<returnValue>strlen(arg1)</returnValue>
|
||||
<arg nr="1">
|
||||
<not-null/>
|
||||
<not-uninit/>
|
||||
|
|
|
@ -545,6 +545,8 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
|
|||
leakignore.insert(name);
|
||||
else if (functionnodename == "use-retval")
|
||||
_useretval.insert(name);
|
||||
else if (functionnodename == "returnValue" && functionnode->GetText())
|
||||
_returnValue[name] = functionnode->GetText();
|
||||
else if (functionnodename == "arg") {
|
||||
const char* argNrString = functionnode->Attribute("nr");
|
||||
if (!argNrString)
|
||||
|
@ -985,6 +987,14 @@ bool Library::isUseRetVal(const Token* ftok) const
|
|||
_useretval.find(getFunctionName(ftok)) != _useretval.end());
|
||||
}
|
||||
|
||||
std::string Library::returnValue(const Token *ftok) const
|
||||
{
|
||||
if (isNotLibraryFunction(ftok))
|
||||
return std::string();
|
||||
std::map<std::string, std::string>::const_iterator it = _returnValue.find(getFunctionName(ftok));
|
||||
return it != _returnValue.end() ? it->second : std::string();
|
||||
}
|
||||
|
||||
bool Library::isnoreturn(const Token *ftok) const
|
||||
{
|
||||
if (ftok->function() && ftok->function()->isAttributeNoreturn())
|
||||
|
|
|
@ -165,6 +165,8 @@ public:
|
|||
|
||||
bool isUseRetVal(const Token* ftok) const;
|
||||
|
||||
std::string returnValue(const Token *ftok) const;
|
||||
|
||||
bool isnoreturn(const Token *ftok) const;
|
||||
bool isnotnoreturn(const Token *ftok) const;
|
||||
|
||||
|
@ -478,6 +480,7 @@ private:
|
|||
std::map<std::string, AllocFunc> _dealloc; // deallocation functions
|
||||
std::set<std::string> _functions;
|
||||
std::map<std::string, bool> _noreturn; // is function noreturn?
|
||||
std::map<std::string, std::string> _returnValue;
|
||||
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> _processAfterCode;
|
||||
|
|
|
@ -407,7 +407,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
|||
}
|
||||
|
||||
// Calculations..
|
||||
else if ((parent->isArithmeticalOp() || parent->isComparisonOp() || (parent->tokType() == Token::eBitOp)) &&
|
||||
else if ((parent->isArithmeticalOp() || parent->isComparisonOp() || (parent->tokType() == Token::eBitOp) || (parent->tokType() == Token::eLogicalOp)) &&
|
||||
parent->astOperand1() &&
|
||||
parent->astOperand2()) {
|
||||
const bool known = ((parent->astOperand1()->values.size() == 1U &&
|
||||
|
@ -503,11 +503,17 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
|
|||
setTokenValue(parent, result);
|
||||
break;
|
||||
case '&':
|
||||
if (parent->str() == "&")
|
||||
result.intvalue = value1->intvalue & value2->intvalue;
|
||||
else
|
||||
result.intvalue = value1->intvalue && value2->intvalue;
|
||||
setTokenValue(parent, result);
|
||||
break;
|
||||
case '|':
|
||||
if (parent->str() == "|")
|
||||
result.intvalue = value1->intvalue | value2->intvalue;
|
||||
else
|
||||
result.intvalue = value1->intvalue || value2->intvalue;
|
||||
setTokenValue(parent, result);
|
||||
break;
|
||||
case '^':
|
||||
|
@ -2323,6 +2329,68 @@ static void valueFlowSwitchVariable(TokenList *tokenlist, SymbolDatabase* symbol
|
|||
}
|
||||
}
|
||||
|
||||
static void setTokenValues(Token *tok, const std::list<ValueFlow::Value> &values)
|
||||
{
|
||||
for (std::list<ValueFlow::Value>::const_iterator it = values.begin(); it != values.end(); ++it) {
|
||||
const ValueFlow::Value &value = *it;
|
||||
if (!value.tokvalue)
|
||||
setTokenValue(tok, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void valueFlowLibraryFunction(Token *tok, const std::string &returnValue, const Settings *settings)
|
||||
{
|
||||
std::istringstream istr(returnValue);
|
||||
TokenList tokenList(settings);
|
||||
if (!tokenList.createTokens(istr))
|
||||
return;
|
||||
|
||||
const Token *arg1 = tok->astOperand2();
|
||||
while (arg1 && arg1->str() == ",")
|
||||
arg1 = arg1->astOperand1();
|
||||
if (Token::findsimplematch(tokenList.front(), "arg1") && !arg1)
|
||||
return;
|
||||
|
||||
if (Token::simpleMatch(tokenList.front(), "strlen ( arg1 )") && arg1) {
|
||||
for (std::list<ValueFlow::Value>::const_iterator it = arg1->values.begin(); it != arg1->values.end(); ++it) {
|
||||
const ValueFlow::Value &value = *it;
|
||||
if (value.tokvalue && value.tokvalue->tokType() == Token::eString) {
|
||||
ValueFlow::Value retval(value); // copy all "inconclusive", "condition", etc attributes
|
||||
// set return value..
|
||||
retval.tokvalue = nullptr;
|
||||
retval.intvalue = Token::getStrLength(value.tokvalue);
|
||||
setTokenValue(tok, retval);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// combine operators, set links, etc..
|
||||
for (Token *tok2 = tokenList.front(); tok2; tok2 = tok2->next()) {
|
||||
if (Token::Match(tok2, "[!<>=] =")) {
|
||||
tok2->str(tok2->str() + "=");
|
||||
tok2->deleteNext();
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate expression
|
||||
tokenList.createAst();
|
||||
valueFlowNumber(&tokenList);
|
||||
for (Token *tok2 = tokenList.front(); tok2; tok2 = tok2->next()) {
|
||||
if (tok2->str() == "arg1" && arg1) {
|
||||
setTokenValues(tok2, arg1->values);
|
||||
}
|
||||
}
|
||||
|
||||
// Find result..
|
||||
for (const Token *tok2 = tokenList.front(); tok2; tok2 = tok2->next()) {
|
||||
if (!tok2->astParent() && !tok2->values.empty()) {
|
||||
setTokenValues(tok, tok2->values);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
||||
{
|
||||
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||
|
@ -2330,8 +2398,13 @@ static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger,
|
|||
continue;
|
||||
|
||||
const Function * const currentFunction = tok->function();
|
||||
if (!currentFunction)
|
||||
if (!currentFunction) {
|
||||
// library function?
|
||||
const std::string returnValue(settings->library.returnValue(tok));
|
||||
if (!returnValue.empty())
|
||||
valueFlowLibraryFunction(tok->next(), returnValue, settings);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Function scope..
|
||||
const Scope * const functionScope = currentFunction->functionScope;
|
||||
|
|
Loading…
Reference in New Issue