Fixed #7668 (ValueFlow: return value from abs)

This commit is contained in:
Daniel Marjamäki 2016-10-17 13:05:19 +02:00
parent 0e9bf9f0c6
commit fae4a4dacf
4 changed files with 93 additions and 4 deletions

View File

@ -10,6 +10,7 @@
<pure/> <pure/>
<noreturn>false</noreturn> <noreturn>false</noreturn>
<leak-ignore/> <leak-ignore/>
<returnValue>arg1&gt;0?arg1:-arg1</returnValue>
<arg nr="1"> <arg nr="1">
<not-uninit/> <not-uninit/>
<not-bool/> <not-bool/>
@ -1584,6 +1585,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<pure/> <pure/>
<noreturn>false</noreturn> <noreturn>false</noreturn>
<leak-ignore/> <leak-ignore/>
<returnValue>arg1&gt;='0' &amp;&amp; arg1&lt;='9'</returnValue>
<arg nr="1"> <arg nr="1">
<not-uninit/> <not-uninit/>
<valid>0:255</valid> <valid>0:255</valid>
@ -3034,6 +3036,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<pure/> <pure/>
<noreturn>false</noreturn> <noreturn>false</noreturn>
<leak-ignore/> <leak-ignore/>
<returnValue>strlen(arg1)</returnValue>
<arg nr="1"> <arg nr="1">
<not-null/> <not-null/>
<not-uninit/> <not-uninit/>

View File

@ -545,6 +545,8 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
leakignore.insert(name); leakignore.insert(name);
else if (functionnodename == "use-retval") else if (functionnodename == "use-retval")
_useretval.insert(name); _useretval.insert(name);
else if (functionnodename == "returnValue" && functionnode->GetText())
_returnValue[name] = functionnode->GetText();
else if (functionnodename == "arg") { else if (functionnodename == "arg") {
const char* argNrString = functionnode->Attribute("nr"); const char* argNrString = functionnode->Attribute("nr");
if (!argNrString) if (!argNrString)
@ -985,6 +987,14 @@ bool Library::isUseRetVal(const Token* ftok) const
_useretval.find(getFunctionName(ftok)) != _useretval.end()); _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 bool Library::isnoreturn(const Token *ftok) const
{ {
if (ftok->function() && ftok->function()->isAttributeNoreturn()) if (ftok->function() && ftok->function()->isAttributeNoreturn())

View File

@ -165,6 +165,8 @@ public:
bool isUseRetVal(const Token* ftok) const; bool isUseRetVal(const Token* ftok) const;
std::string returnValue(const Token *ftok) const;
bool isnoreturn(const Token *ftok) const; bool isnoreturn(const Token *ftok) const;
bool isnotnoreturn(const Token *ftok) const; bool isnotnoreturn(const Token *ftok) const;
@ -478,6 +480,7 @@ private:
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;
std::map<std::string, bool> _noreturn; // is function noreturn? 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::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;

View File

@ -407,7 +407,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
} }
// Calculations.. // 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->astOperand1() &&
parent->astOperand2()) { parent->astOperand2()) {
const bool known = ((parent->astOperand1()->values.size() == 1U && const bool known = ((parent->astOperand1()->values.size() == 1U &&
@ -503,11 +503,17 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
setTokenValue(parent, result); setTokenValue(parent, result);
break; break;
case '&': case '&':
result.intvalue = value1->intvalue & value2->intvalue; if (parent->str() == "&")
result.intvalue = value1->intvalue & value2->intvalue;
else
result.intvalue = value1->intvalue && value2->intvalue;
setTokenValue(parent, result); setTokenValue(parent, result);
break; break;
case '|': case '|':
result.intvalue = value1->intvalue | value2->intvalue; if (parent->str() == "|")
result.intvalue = value1->intvalue | value2->intvalue;
else
result.intvalue = value1->intvalue || value2->intvalue;
setTokenValue(parent, result); setTokenValue(parent, result);
break; break;
case '^': 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) static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
{ {
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) { for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
@ -2330,8 +2398,13 @@ static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger,
continue; continue;
const Function * const currentFunction = tok->function(); 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; continue;
}
// Function scope.. // Function scope..
const Scope * const functionScope = currentFunction->functionScope; const Scope * const functionScope = currentFunction->functionScope;