parent
b444c002e2
commit
496b45f27b
|
@ -50,6 +50,20 @@ std::size_t ExprIdToken::Hash::operator()(ExprIdToken etok) const
|
||||||
|
|
||||||
void ProgramMemory::setValue(const Token* expr, const ValueFlow::Value& value) {
|
void ProgramMemory::setValue(const Token* expr, const ValueFlow::Value& value) {
|
||||||
mValues[expr] = value;
|
mValues[expr] = value;
|
||||||
|
ValueFlow::Value subvalue = value;
|
||||||
|
const Token* subexpr = solveExprValue(
|
||||||
|
expr,
|
||||||
|
[&](const Token* tok) -> std::vector<MathLib::bigint> {
|
||||||
|
if (tok->hasKnownIntValue())
|
||||||
|
return {tok->values().front().intvalue};
|
||||||
|
MathLib::bigint result = 0;
|
||||||
|
if (getIntValue(tok->exprId(), &result))
|
||||||
|
return {result};
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
subvalue);
|
||||||
|
if (subexpr)
|
||||||
|
mValues[subexpr] = subvalue;
|
||||||
}
|
}
|
||||||
const ValueFlow::Value* ProgramMemory::getValue(nonneg int exprid, bool impossible) const
|
const ValueFlow::Value* ProgramMemory::getValue(nonneg int exprid, bool impossible) const
|
||||||
{
|
{
|
||||||
|
@ -77,7 +91,7 @@ void ProgramMemory::setIntValue(const Token* expr, MathLib::bigint value, bool i
|
||||||
ValueFlow::Value v(value);
|
ValueFlow::Value v(value);
|
||||||
if (impossible)
|
if (impossible)
|
||||||
v.setImpossible();
|
v.setImpossible();
|
||||||
mValues[expr] = v;
|
setValue(expr, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProgramMemory::getTokValue(nonneg int exprid, const Token** result) const
|
bool ProgramMemory::getTokValue(nonneg int exprid, const Token** result) const
|
||||||
|
@ -122,7 +136,7 @@ void ProgramMemory::setContainerSizeValue(const Token* expr, MathLib::bigint val
|
||||||
v.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
v.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||||
if (!isEqual)
|
if (!isEqual)
|
||||||
v.valueKind = ValueFlow::Value::ValueKind::Impossible;
|
v.valueKind = ValueFlow::Value::ValueKind::Impossible;
|
||||||
mValues[expr] = v;
|
setValue(expr, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgramMemory::setUnknown(const Token* expr) {
|
void ProgramMemory::setUnknown(const Token* expr) {
|
||||||
|
|
|
@ -2936,38 +2936,43 @@ static Analyzer::Result valueFlowForwardExpression(Token* startToken,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Token* parseBinaryIntOp(const Token* expr, MathLib::bigint& known)
|
static const Token* parseBinaryIntOp(const Token* expr,
|
||||||
|
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
|
||||||
|
MathLib::bigint& known)
|
||||||
{
|
{
|
||||||
if (!expr)
|
if (!expr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!expr->astOperand1() || !expr->astOperand2())
|
if (!expr->astOperand1() || !expr->astOperand2())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (expr->astOperand1()->exprId() == 0 && !expr->astOperand1()->hasKnownIntValue())
|
if (expr->astOperand1()->exprId() == 0 && expr->astOperand2()->exprId() == 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (expr->astOperand2()->exprId() == 0 && !expr->astOperand2()->hasKnownIntValue())
|
std::vector<MathLib::bigint> x1 = eval(expr->astOperand1());
|
||||||
|
std::vector<MathLib::bigint> x2 = eval(expr->astOperand2());
|
||||||
|
if (expr->astOperand1()->exprId() == 0 && x1.empty())
|
||||||
|
return nullptr;
|
||||||
|
if (expr->astOperand2()->exprId() == 0 && x2.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
const Token* knownTok = nullptr;
|
|
||||||
const Token* varTok = nullptr;
|
const Token* varTok = nullptr;
|
||||||
if (expr->astOperand1()->hasKnownIntValue() && !expr->astOperand2()->hasKnownIntValue()) {
|
if (!x1.empty() && x2.empty()) {
|
||||||
varTok = expr->astOperand2();
|
varTok = expr->astOperand2();
|
||||||
knownTok = expr->astOperand1();
|
known = x1.front();
|
||||||
} else if (expr->astOperand2()->hasKnownIntValue() && !expr->astOperand1()->hasKnownIntValue()) {
|
} else if (x1.empty() && !x2.empty()) {
|
||||||
varTok = expr->astOperand1();
|
varTok = expr->astOperand1();
|
||||||
knownTok = expr->astOperand2();
|
known = x2.front();
|
||||||
}
|
}
|
||||||
if (knownTok)
|
|
||||||
known = knownTok->values().front().intvalue;
|
|
||||||
return varTok;
|
return varTok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
|
const Token* solveExprValue(const Token* expr,
|
||||||
|
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
|
||||||
|
ValueFlow::Value& value)
|
||||||
{
|
{
|
||||||
if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
|
if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
|
||||||
return expr;
|
return expr;
|
||||||
if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
|
if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
|
||||||
return expr;
|
return expr;
|
||||||
MathLib::bigint intval;
|
MathLib::bigint intval;
|
||||||
const Token* binaryTok = parseBinaryIntOp(expr, intval);
|
const Token* binaryTok = parseBinaryIntOp(expr, eval, intval);
|
||||||
bool rhs = astIsRHS(binaryTok);
|
bool rhs = astIsRHS(binaryTok);
|
||||||
// If its on the rhs, then -1 multiplication is needed, which is not possible with simple delta analysis used currently for symbolic values
|
// If its on the rhs, then -1 multiplication is needed, which is not possible with simple delta analysis used currently for symbolic values
|
||||||
if (value.isSymbolicValue() && rhs && Token::simpleMatch(expr, "-"))
|
if (value.isSymbolicValue() && rhs && Token::simpleMatch(expr, "-"))
|
||||||
|
@ -2976,30 +2981,42 @@ static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
|
||||||
switch (expr->str()[0]) {
|
switch (expr->str()[0]) {
|
||||||
case '+': {
|
case '+': {
|
||||||
value.intvalue -= intval;
|
value.intvalue -= intval;
|
||||||
return solveExprValue(binaryTok, value);
|
return solveExprValue(binaryTok, eval, value);
|
||||||
}
|
}
|
||||||
case '-': {
|
case '-': {
|
||||||
if (rhs)
|
if (rhs)
|
||||||
value.intvalue = intval - value.intvalue;
|
value.intvalue = intval - value.intvalue;
|
||||||
else
|
else
|
||||||
value.intvalue += intval;
|
value.intvalue += intval;
|
||||||
return solveExprValue(binaryTok, value);
|
return solveExprValue(binaryTok, eval, value);
|
||||||
}
|
}
|
||||||
case '*': {
|
case '*': {
|
||||||
if (intval == 0)
|
if (intval == 0)
|
||||||
break;
|
break;
|
||||||
value.intvalue /= intval;
|
value.intvalue /= intval;
|
||||||
return solveExprValue(binaryTok, value);
|
return solveExprValue(binaryTok, eval, value);
|
||||||
}
|
}
|
||||||
case '^': {
|
case '^': {
|
||||||
value.intvalue ^= intval;
|
value.intvalue ^= intval;
|
||||||
return solveExprValue(binaryTok, value);
|
return solveExprValue(binaryTok, eval, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
|
||||||
|
{
|
||||||
|
return solveExprValue(
|
||||||
|
expr,
|
||||||
|
[](const Token* tok) -> std::vector<MathLib::bigint> {
|
||||||
|
if (tok->hasKnownIntValue())
|
||||||
|
return {tok->values().front().intvalue};
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist)
|
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist)
|
||||||
{
|
{
|
||||||
const Token* expr = solveExprValue(exprTok, value);
|
const Token* expr = solveExprValue(exprTok, value);
|
||||||
|
|
|
@ -503,6 +503,10 @@ ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, Math
|
||||||
|
|
||||||
CPPCHECKLIB ValuePtr<InferModel> makeIntegralInferModel();
|
CPPCHECKLIB ValuePtr<InferModel> makeIntegralInferModel();
|
||||||
|
|
||||||
|
const Token* solveExprValue(const Token* expr,
|
||||||
|
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
|
||||||
|
ValueFlow::Value& value);
|
||||||
|
|
||||||
std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
|
std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
|
||||||
bool escape = false,
|
bool escape = false,
|
||||||
ValueFlow::Value::ErrorPath errorPath = ValueFlow::Value::ErrorPath{});
|
ValueFlow::Value::ErrorPath errorPath = ValueFlow::Value::ErrorPath{});
|
||||||
|
|
|
@ -3612,6 +3612,17 @@ private:
|
||||||
" int a[ 2 ] = { [ 0 ] = *p++, [ 1 ] = 1 };\n"
|
" int a[ 2 ] = { [ 0 ] = *p++, [ 1 ] = 1 };\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: p\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: p\n", errout.str());
|
||||||
|
|
||||||
|
valueFlowUninit("void f(int height) {\n"
|
||||||
|
" int a[11];\n"
|
||||||
|
" int *p = a;\n"
|
||||||
|
" int step = 2;\n"
|
||||||
|
" for (int i = 0; i < (height * step); i += step)\n"
|
||||||
|
" *p++ = 0;\n"
|
||||||
|
" for (int i = 0; i < height; i++)\n"
|
||||||
|
" if (a[i]) {}\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void uninitStructMember() { // struct members
|
void uninitStructMember() { // struct members
|
||||||
|
|
Loading…
Reference in New Issue