Fix 10578: Value not impossible after check (#3549)
This commit is contained in:
parent
a50596df72
commit
035c70c441
|
@ -215,6 +215,14 @@ bool astIsGenericChar(const Token* tok)
|
||||||
return !astIsPointer(tok) && tok && tok->valueType() && (tok->valueType()->type == ValueType::Type::CHAR || tok->valueType()->type == ValueType::Type::WCHAR_T);
|
return !astIsPointer(tok) && tok && tok->valueType() && (tok->valueType()->type == ValueType::Type::CHAR || tok->valueType()->type == ValueType::Type::WCHAR_T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool astIsPrimitive(const Token* tok)
|
||||||
|
{
|
||||||
|
const ValueType* vt = tok ? tok->valueType() : nullptr;
|
||||||
|
if (!vt)
|
||||||
|
return false;
|
||||||
|
return vt->isPrimitive();
|
||||||
|
}
|
||||||
|
|
||||||
bool astIsIntegral(const Token *tok, bool unknown)
|
bool astIsIntegral(const Token *tok, bool unknown)
|
||||||
{
|
{
|
||||||
const ValueType *vt = tok ? tok->valueType() : nullptr;
|
const ValueType *vt = tok ? tok->valueType() : nullptr;
|
||||||
|
@ -1950,6 +1958,9 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
|
||||||
return false;
|
return false;
|
||||||
if (tok->isKeyword() && !isCPPCastKeyword(tok) && tok->str().compare(0,8,"operator") != 0)
|
if (tok->isKeyword() && !isCPPCastKeyword(tok) && tok->str().compare(0,8,"operator") != 0)
|
||||||
return false;
|
return false;
|
||||||
|
// A functional cast won't modify the variable
|
||||||
|
if (Token::Match(tok, "%type% (|{") && tok->tokType() == Token::eType && astIsPrimitive(tok->next()))
|
||||||
|
return false;
|
||||||
const Token * parenTok = tok->next();
|
const Token * parenTok = tok->next();
|
||||||
if (Token::simpleMatch(parenTok, "<") && parenTok->link())
|
if (Token::simpleMatch(parenTok, "<") && parenTok->link())
|
||||||
parenTok = parenTok->link()->next();
|
parenTok = parenTok->link()->next();
|
||||||
|
|
|
@ -64,6 +64,7 @@ bool astHasToken(const Token* root, const Token * tok);
|
||||||
|
|
||||||
bool astHasVar(const Token * tok, nonneg int varid);
|
bool astHasVar(const Token * tok, nonneg int varid);
|
||||||
|
|
||||||
|
bool astIsPrimitive(const Token* tok);
|
||||||
/** Is expression a 'signed char' if no promotion is used */
|
/** Is expression a 'signed char' if no promotion is used */
|
||||||
bool astIsSignedChar(const Token *tok);
|
bool astIsSignedChar(const Token *tok);
|
||||||
/** Is expression a 'char' if no promotion is used? */
|
/** Is expression a 'char' if no promotion is used? */
|
||||||
|
|
|
@ -973,6 +973,10 @@ void CheckIO::checkFormatString(const Token * const tok,
|
||||||
std::string specifier;
|
std::string specifier;
|
||||||
bool done = false;
|
bool done = false;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
|
if (i == formatString.end()) {
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
switch (*i) {
|
switch (*i) {
|
||||||
case 's':
|
case 's':
|
||||||
if (argListTok->tokType() != Token::eString &&
|
if (argListTok->tokType() != Token::eString &&
|
||||||
|
@ -1242,7 +1246,7 @@ void CheckIO::checkFormatString(const Token * const tok,
|
||||||
case 'h': // Can be 'hh' (signed char or unsigned char) or 'h' (short int or unsigned short int)
|
case 'h': // Can be 'hh' (signed char or unsigned char) or 'h' (short int or unsigned short int)
|
||||||
case 'l': { // Can be 'll' (long long int or unsigned long long int) or 'l' (long int or unsigned long int)
|
case 'l': { // Can be 'll' (long long int or unsigned long long int) or 'l' (long int or unsigned long int)
|
||||||
// If the next character is the same (which makes 'hh' or 'll') then expect another alphabetical character
|
// If the next character is the same (which makes 'hh' or 'll') then expect another alphabetical character
|
||||||
if (i != formatString.end() && (i + 1) != formatString.end() && *(i + 1) == *i) {
|
if ((i + 1) != formatString.end() && *(i + 1) == *i) {
|
||||||
if ((i + 2) != formatString.end() && !isalpha(*(i + 2))) {
|
if ((i + 2) != formatString.end() && !isalpha(*(i + 2))) {
|
||||||
std::string modifier;
|
std::string modifier;
|
||||||
modifier += *i;
|
modifier += *i;
|
||||||
|
@ -1254,7 +1258,6 @@ void CheckIO::checkFormatString(const Token * const tok,
|
||||||
specifier += *i++;
|
specifier += *i++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (i != formatString.end()) {
|
|
||||||
if ((i + 1) != formatString.end() && !isalpha(*(i + 1))) {
|
if ((i + 1) != formatString.end() && !isalpha(*(i + 1))) {
|
||||||
std::string modifier;
|
std::string modifier;
|
||||||
modifier += *i;
|
modifier += *i;
|
||||||
|
@ -1263,9 +1266,6 @@ void CheckIO::checkFormatString(const Token * const tok,
|
||||||
} else {
|
} else {
|
||||||
specifier = *i++;
|
specifier = *i++;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -263,6 +263,15 @@ struct ReverseTraversal {
|
||||||
tok = parent;
|
tok = parent;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (tok->str() == "case") {
|
||||||
|
const Scope* scope = tok->scope();
|
||||||
|
while (scope && scope->type != Scope::eSwitch)
|
||||||
|
scope = scope->nestedIn;
|
||||||
|
if (!scope || scope->type != Scope::eSwitch)
|
||||||
|
break;
|
||||||
|
tok = tok->tokAt(scope->bodyStart->index() - tok->index() - 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!update(tok))
|
if (!update(tok))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6504,6 +6504,8 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
|
||||||
valuetype.sign = ValueType::Sign::UNSIGNED;
|
valuetype.sign = ValueType::Sign::UNSIGNED;
|
||||||
else if (tok->previous()->isSigned())
|
else if (tok->previous()->isSigned())
|
||||||
valuetype.sign = ValueType::Sign::SIGNED;
|
valuetype.sign = ValueType::Sign::SIGNED;
|
||||||
|
else if (valuetype.isIntegral() && valuetype.type != ValueType::UNKNOWN_INT)
|
||||||
|
valuetype.sign = mDefaultSignedness;
|
||||||
setValueType(tok, valuetype);
|
setValueType(tok, valuetype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -356,7 +356,13 @@ static void combineValueProperties(const ValueFlow::Value &value1, const ValueFl
|
||||||
static const Token *getCastTypeStartToken(const Token *parent)
|
static const Token *getCastTypeStartToken(const Token *parent)
|
||||||
{
|
{
|
||||||
// TODO: This might be a generic utility function?
|
// TODO: This might be a generic utility function?
|
||||||
if (!parent || parent->str() != "(")
|
if (!Token::Match(parent, "{|("))
|
||||||
|
return nullptr;
|
||||||
|
// Functional cast
|
||||||
|
if (parent->isBinaryOp() && Token::Match(parent->astOperand1(), "%type% (|{") &&
|
||||||
|
parent->astOperand1()->tokType() == Token::eType && astIsPrimitive(parent))
|
||||||
|
return parent->astOperand1();
|
||||||
|
if (parent->str() != "(")
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!parent->astOperand2() && Token::Match(parent,"( %name%"))
|
if (!parent->astOperand2() && Token::Match(parent,"( %name%"))
|
||||||
return parent->next();
|
return parent->next();
|
||||||
|
@ -2328,6 +2334,9 @@ struct ValueFlowAnalyzer : Analyzer {
|
||||||
} else if (getSettings()->library.getFunction(tok)) {
|
} else if (getSettings()->library.getFunction(tok)) {
|
||||||
// Assume library function doesn't modify user-global variables
|
// Assume library function doesn't modify user-global variables
|
||||||
return Action::None;
|
return Action::None;
|
||||||
|
// Function cast does not modify global variables
|
||||||
|
} else if (tok->tokType() == Token::eType && astIsPrimitive(tok->next())) {
|
||||||
|
return Action::None;
|
||||||
} else {
|
} else {
|
||||||
return Action::Invalid;
|
return Action::Invalid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -516,6 +516,12 @@ private:
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::list<ValueFlow::Value> removeImpossible(std::list<ValueFlow::Value> values)
|
||||||
|
{
|
||||||
|
values.remove_if(std::mem_fn(&ValueFlow::Value::isImpossible));
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
void valueFlowNumber() {
|
void valueFlowNumber() {
|
||||||
ASSERT_EQUALS(123, valueOfTok("x=123;", "123").intvalue);
|
ASSERT_EQUALS(123, valueOfTok("x=123;", "123").intvalue);
|
||||||
ASSERT_EQUALS_DOUBLE(192.0, valueOfTok("x=0x0.3p10;", "0x0.3p10").floatValue, 1e-5); // 3 * 16^-1 * 2^10 = 192
|
ASSERT_EQUALS_DOUBLE(192.0, valueOfTok("x=0x0.3p10;", "0x0.3p10").floatValue, 1e-5); // 3 * 16^-1 * 2^10 = 192
|
||||||
|
@ -3015,7 +3021,22 @@ private:
|
||||||
" return 0; \n"
|
" return 0; \n"
|
||||||
"}\n";
|
"}\n";
|
||||||
ASSERT_EQUALS(true, testValueOfX(code, 6U, 63));
|
ASSERT_EQUALS(true, testValueOfX(code, 6U, 63));
|
||||||
TODO_ASSERT_EQUALS(true, false, testValueOfXImpossible(code, 6U, 64));
|
ASSERT_EQUALS(true, testValueOfXImpossible(code, 6U, 64));
|
||||||
|
|
||||||
|
code = "long long f(const long long& x, const long long& y) {\n"
|
||||||
|
" switch (s) {\n"
|
||||||
|
" case 0:\n"
|
||||||
|
" if (x >= 64)\n"
|
||||||
|
" return 0;\n"
|
||||||
|
" return long long{y} << long long{x};\n"
|
||||||
|
" case 1:\n"
|
||||||
|
" if (x >= 64) {\n"
|
||||||
|
" }\n"
|
||||||
|
" }\n"
|
||||||
|
" return 0; \n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(true, testValueOfX(code, 6U, 63));
|
||||||
|
ASSERT_EQUALS(true, testValueOfXImpossible(code, 6U, 64));
|
||||||
|
|
||||||
code = "int g(int x) { throw 0; }\n"
|
code = "int g(int x) { throw 0; }\n"
|
||||||
"void f(int x) {\n"
|
"void f(int x) {\n"
|
||||||
|
|
Loading…
Reference in New Issue