Skip to content

Commit 035c70c

Browse files
authored
Fix 10578: Value not impossible after check (#3549)
1 parent a50596d commit 035c70c

7 files changed

Lines changed: 66 additions & 13 deletions

File tree

lib/astutils.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,14 @@ bool astIsGenericChar(const Token* tok)
215215
return !astIsPointer(tok) && tok && tok->valueType() && (tok->valueType()->type == ValueType::Type::CHAR || tok->valueType()->type == ValueType::Type::WCHAR_T);
216216
}
217217

218+
bool astIsPrimitive(const Token* tok)
219+
{
220+
const ValueType* vt = tok ? tok->valueType() : nullptr;
221+
if (!vt)
222+
return false;
223+
return vt->isPrimitive();
224+
}
225+
218226
bool astIsIntegral(const Token *tok, bool unknown)
219227
{
220228
const ValueType *vt = tok ? tok->valueType() : nullptr;
@@ -1950,6 +1958,9 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
19501958
return false;
19511959
if (tok->isKeyword() && !isCPPCastKeyword(tok) && tok->str().compare(0,8,"operator") != 0)
19521960
return false;
1961+
// A functional cast won't modify the variable
1962+
if (Token::Match(tok, "%type% (|{") && tok->tokType() == Token::eType && astIsPrimitive(tok->next()))
1963+
return false;
19531964
const Token * parenTok = tok->next();
19541965
if (Token::simpleMatch(parenTok, "<") && parenTok->link())
19551966
parenTok = parenTok->link()->next();

lib/astutils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ bool astHasToken(const Token* root, const Token * tok);
6464

6565
bool astHasVar(const Token * tok, nonneg int varid);
6666

67+
bool astIsPrimitive(const Token* tok);
6768
/** Is expression a 'signed char' if no promotion is used */
6869
bool astIsSignedChar(const Token *tok);
6970
/** Is expression a 'char' if no promotion is used? */

lib/checkio.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,10 @@ void CheckIO::checkFormatString(const Token * const tok,
973973
std::string specifier;
974974
bool done = false;
975975
while (!done) {
976+
if (i == formatString.end()) {
977+
done = true;
978+
break;
979+
}
976980
switch (*i) {
977981
case 's':
978982
if (argListTok->tokType() != Token::eString &&
@@ -1242,7 +1246,7 @@ void CheckIO::checkFormatString(const Token * const tok,
12421246
case 'h': // Can be 'hh' (signed char or unsigned char) or 'h' (short int or unsigned short int)
12431247
case 'l': { // Can be 'll' (long long int or unsigned long long int) or 'l' (long int or unsigned long int)
12441248
// If the next character is the same (which makes 'hh' or 'll') then expect another alphabetical character
1245-
if (i != formatString.end() && (i + 1) != formatString.end() && *(i + 1) == *i) {
1249+
if ((i + 1) != formatString.end() && *(i + 1) == *i) {
12461250
if ((i + 2) != formatString.end() && !isalpha(*(i + 2))) {
12471251
std::string modifier;
12481252
modifier += *i;
@@ -1254,17 +1258,13 @@ void CheckIO::checkFormatString(const Token * const tok,
12541258
specifier += *i++;
12551259
}
12561260
} else {
1257-
if (i != formatString.end()) {
1258-
if ((i + 1) != formatString.end() && !isalpha(*(i + 1))) {
1259-
std::string modifier;
1260-
modifier += *i;
1261-
invalidLengthModifierError(tok, numFormat, modifier);
1262-
done = true;
1263-
} else {
1264-
specifier = *i++;
1265-
}
1266-
} else {
1261+
if ((i + 1) != formatString.end() && !isalpha(*(i + 1))) {
1262+
std::string modifier;
1263+
modifier += *i;
1264+
invalidLengthModifierError(tok, numFormat, modifier);
12671265
done = true;
1266+
} else {
1267+
specifier = *i++;
12681268
}
12691269
}
12701270
}

lib/reverseanalyzer.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,15 @@ struct ReverseTraversal {
263263
tok = parent;
264264
continue;
265265
}
266+
if (tok->str() == "case") {
267+
const Scope* scope = tok->scope();
268+
while (scope && scope->type != Scope::eSwitch)
269+
scope = scope->nestedIn;
270+
if (!scope || scope->type != Scope::eSwitch)
271+
break;
272+
tok = tok->tokAt(scope->bodyStart->index() - tok->index() - 1);
273+
continue;
274+
}
266275
if (!update(tok))
267276
break;
268277
}

lib/symboldatabase.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6504,6 +6504,8 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
65046504
valuetype.sign = ValueType::Sign::UNSIGNED;
65056505
else if (tok->previous()->isSigned())
65066506
valuetype.sign = ValueType::Sign::SIGNED;
6507+
else if (valuetype.isIntegral() && valuetype.type != ValueType::UNKNOWN_INT)
6508+
valuetype.sign = mDefaultSignedness;
65076509
setValueType(tok, valuetype);
65086510
}
65096511

lib/valueflow.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,13 @@ static void combineValueProperties(const ValueFlow::Value &value1, const ValueFl
356356
static const Token *getCastTypeStartToken(const Token *parent)
357357
{
358358
// TODO: This might be a generic utility function?
359-
if (!parent || parent->str() != "(")
359+
if (!Token::Match(parent, "{|("))
360+
return nullptr;
361+
// Functional cast
362+
if (parent->isBinaryOp() && Token::Match(parent->astOperand1(), "%type% (|{") &&
363+
parent->astOperand1()->tokType() == Token::eType && astIsPrimitive(parent))
364+
return parent->astOperand1();
365+
if (parent->str() != "(")
360366
return nullptr;
361367
if (!parent->astOperand2() && Token::Match(parent,"( %name%"))
362368
return parent->next();
@@ -2328,6 +2334,9 @@ struct ValueFlowAnalyzer : Analyzer {
23282334
} else if (getSettings()->library.getFunction(tok)) {
23292335
// Assume library function doesn't modify user-global variables
23302336
return Action::None;
2337+
// Function cast does not modify global variables
2338+
} else if (tok->tokType() == Token::eType && astIsPrimitive(tok->next())) {
2339+
return Action::None;
23312340
} else {
23322341
return Action::Invalid;
23332342
}

test/testvalueflow.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,12 @@ class TestValueFlow : public TestFixture {
516516
return values;
517517
}
518518

519+
std::list<ValueFlow::Value> removeImpossible(std::list<ValueFlow::Value> values)
520+
{
521+
values.remove_if(std::mem_fn(&ValueFlow::Value::isImpossible));
522+
return values;
523+
}
524+
519525
void valueFlowNumber() {
520526
ASSERT_EQUALS(123, valueOfTok("x=123;", "123").intvalue);
521527
ASSERT_EQUALS_DOUBLE(192.0, valueOfTok("x=0x0.3p10;", "0x0.3p10").floatValue, 1e-5); // 3 * 16^-1 * 2^10 = 192
@@ -3015,7 +3021,22 @@ class TestValueFlow : public TestFixture {
30153021
" return 0; \n"
30163022
"}\n";
30173023
ASSERT_EQUALS(true, testValueOfX(code, 6U, 63));
3018-
TODO_ASSERT_EQUALS(true, false, testValueOfXImpossible(code, 6U, 64));
3024+
ASSERT_EQUALS(true, testValueOfXImpossible(code, 6U, 64));
3025+
3026+
code = "long long f(const long long& x, const long long& y) {\n"
3027+
" switch (s) {\n"
3028+
" case 0:\n"
3029+
" if (x >= 64)\n"
3030+
" return 0;\n"
3031+
" return long long{y} << long long{x};\n"
3032+
" case 1:\n"
3033+
" if (x >= 64) {\n"
3034+
" }\n"
3035+
" }\n"
3036+
" return 0; \n"
3037+
"}\n";
3038+
ASSERT_EQUALS(true, testValueOfX(code, 6U, 63));
3039+
ASSERT_EQUALS(true, testValueOfXImpossible(code, 6U, 64));
30193040

30203041
code = "int g(int x) { throw 0; }\n"
30213042
"void f(int x) {\n"

0 commit comments

Comments
 (0)