ExprEngine; better handling of containers
This commit is contained in:
parent
5497e8ed67
commit
f792cabc2b
@ -1454,6 +1454,25 @@ static ExprEngine::ValuePtr getValueRangeFromValueType(const std::string &name,
|
|||||||
return ExprEngine::ValuePtr();
|
return ExprEngine::ValuePtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ExprEngine::ValuePtr getValueRangeFromValueType(const ValueType *valueType, Data &data)
|
||||||
|
{
|
||||||
|
if (!valueType || valueType->pointer)
|
||||||
|
return ExprEngine::ValuePtr();
|
||||||
|
if (valueType->container) {
|
||||||
|
ExprEngine::ValuePtr value;
|
||||||
|
if (valueType->container->stdStringLike)
|
||||||
|
value = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), -128, 127);
|
||||||
|
else if (valueType->containerTypeToken) {
|
||||||
|
ValueType vt = ValueType::parseDecl(valueType->containerTypeToken, data.settings);
|
||||||
|
value = getValueRangeFromValueType(&vt, data);
|
||||||
|
} else
|
||||||
|
return ExprEngine::ValuePtr();
|
||||||
|
auto bufferSize = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 0, ~0U);
|
||||||
|
return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), bufferSize, value, false, false, false);
|
||||||
|
}
|
||||||
|
return getValueRangeFromValueType(data.getNewSymbolName(), valueType, *data.settings);
|
||||||
|
}
|
||||||
|
|
||||||
static void call(const std::vector<ExprEngine::Callback> &callbacks, const Token *tok, ExprEngine::ValuePtr value, Data *dataBase)
|
static void call(const std::vector<ExprEngine::Callback> &callbacks, const Token *tok, ExprEngine::ValuePtr value, Data *dataBase)
|
||||||
{
|
{
|
||||||
if (value) {
|
if (value) {
|
||||||
@ -1616,14 +1635,11 @@ static ExprEngine::ValuePtr executeAssign(const Token *tok, Data &data)
|
|||||||
const ValueType * const vt1 = tok->astOperand1() ? tok->astOperand1()->valueType() : nullptr;
|
const ValueType * const vt1 = tok->astOperand1() ? tok->astOperand1()->valueType() : nullptr;
|
||||||
const ValueType * const vt2 = tok->astOperand2() ? tok->astOperand2()->valueType() : nullptr;
|
const ValueType * const vt2 = tok->astOperand2() ? tok->astOperand2()->valueType() : nullptr;
|
||||||
|
|
||||||
if (vt1 && vt1->pointer == 0 && vt1->isIntegral())
|
rhsValue = getValueRangeFromValueType(vt1, data);
|
||||||
rhsValue = getValueRangeFromValueType(data.getNewSymbolName(), vt1, *data.settings);
|
if (!rhsValue && vt2 && vt2->pointer == 0) {
|
||||||
|
rhsValue = getValueRangeFromValueType(vt2, data);
|
||||||
else if (vt2 && vt2->container && vt2->container->stdStringLike) {
|
if (rhsValue)
|
||||||
auto size = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 0, ~0ULL);
|
call(data.callbacks, tok->astOperand2(), rhsValue, &data);
|
||||||
auto value = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), -128, 127);
|
|
||||||
rhsValue = std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), size, value, false, false, false);
|
|
||||||
call(data.callbacks, tok->astOperand2(), rhsValue, &data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1767,13 +1783,13 @@ static ExprEngine::ValuePtr executeFunctionCall(const Token *tok, Data &data)
|
|||||||
if (auto arrayValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(val)) {
|
if (auto arrayValue = std::dynamic_pointer_cast<ExprEngine::ArrayValue>(val)) {
|
||||||
ValueType vt(*argtok->valueType());
|
ValueType vt(*argtok->valueType());
|
||||||
vt.pointer = 0;
|
vt.pointer = 0;
|
||||||
auto anyVal = getValueRangeFromValueType(data.getNewSymbolName(), &vt, *data.settings);
|
auto anyVal = getValueRangeFromValueType(&vt, data);
|
||||||
arrayValue->assign(ExprEngine::ValuePtr(), anyVal);
|
arrayValue->assign(ExprEngine::ValuePtr(), anyVal);
|
||||||
} else if (auto addressOf = std::dynamic_pointer_cast<ExprEngine::AddressOfValue>(val)) {
|
} else if (auto addressOf = std::dynamic_pointer_cast<ExprEngine::AddressOfValue>(val)) {
|
||||||
ValueType vt(*argtok->valueType());
|
ValueType vt(*argtok->valueType());
|
||||||
vt.pointer = 0;
|
vt.pointer = 0;
|
||||||
if (vt.isIntegral() && argtok->valueType()->pointer == 1)
|
if (vt.isIntegral() && argtok->valueType()->pointer == 1)
|
||||||
data.assignValue(argtok, addressOf->varId, getValueRangeFromValueType(data.getNewSymbolName(), &vt, *data.settings));
|
data.assignValue(argtok, addressOf->varId, getValueRangeFromValueType(&vt, data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1826,7 +1842,7 @@ static ExprEngine::ValuePtr executeFunctionCall(const Token *tok, Data &data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto val = getValueRangeFromValueType(data.getNewSymbolName(), tok->valueType(), *data.settings);
|
auto val = getValueRangeFromValueType(tok->valueType(), data);
|
||||||
call(data.callbacks, tok, val, &data);
|
call(data.callbacks, tok, val, &data);
|
||||||
data.functionCall();
|
data.functionCall();
|
||||||
return val;
|
return val;
|
||||||
@ -1867,7 +1883,7 @@ static ExprEngine::ValuePtr executeCast(const Token *tok, Data &data)
|
|||||||
|
|
||||||
::ValueType vt(*tok->valueType());
|
::ValueType vt(*tok->valueType());
|
||||||
vt.pointer = 0;
|
vt.pointer = 0;
|
||||||
auto range = getValueRangeFromValueType(data.getNewSymbolName(), &vt, *data.settings);
|
auto range = getValueRangeFromValueType(&vt, data);
|
||||||
|
|
||||||
if (tok->valueType()->pointer == 0)
|
if (tok->valueType()->pointer == 0)
|
||||||
return range;
|
return range;
|
||||||
@ -1888,7 +1904,7 @@ static ExprEngine::ValuePtr executeCast(const Token *tok, Data &data)
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
val = getValueRangeFromValueType(data.getNewSymbolName(), tok->valueType(), *data.settings);
|
val = getValueRangeFromValueType(tok->valueType(), data);
|
||||||
call(data.callbacks, tok, val, &data);
|
call(data.callbacks, tok, val, &data);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@ -1896,7 +1912,7 @@ static ExprEngine::ValuePtr executeCast(const Token *tok, Data &data)
|
|||||||
static ExprEngine::ValuePtr executeDot(const Token *tok, Data &data)
|
static ExprEngine::ValuePtr executeDot(const Token *tok, Data &data)
|
||||||
{
|
{
|
||||||
if (!tok->astOperand1() || !tok->astOperand1()->varId()) {
|
if (!tok->astOperand1() || !tok->astOperand1()->varId()) {
|
||||||
auto v = getValueRangeFromValueType(data.getNewSymbolName(), tok->valueType(), *data.settings);
|
auto v = getValueRangeFromValueType(tok->valueType(), data);
|
||||||
call(data.callbacks, tok, v, &data);
|
call(data.callbacks, tok, v, &data);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
@ -1923,7 +1939,7 @@ static ExprEngine::ValuePtr executeDot(const Token *tok, Data &data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!structValue) {
|
if (!structValue) {
|
||||||
auto v = getValueRangeFromValueType(data.getNewSymbolName(), tok->valueType(), *data.settings);
|
auto v = getValueRangeFromValueType(tok->valueType(), data);
|
||||||
if (!v)
|
if (!v)
|
||||||
v = std::make_shared<ExprEngine::BailoutValue>();
|
v = std::make_shared<ExprEngine::BailoutValue>();
|
||||||
call(data.callbacks, tok, v, &data);
|
call(data.callbacks, tok, v, &data);
|
||||||
@ -1940,7 +1956,7 @@ static void streamReadSetValue(const Token *tok, Data &data)
|
|||||||
{
|
{
|
||||||
if (!tok || !tok->valueType())
|
if (!tok || !tok->valueType())
|
||||||
return;
|
return;
|
||||||
auto rangeValue = getValueRangeFromValueType(data.getNewSymbolName(), tok->valueType(), *data.settings);
|
auto rangeValue = getValueRangeFromValueType(tok->valueType(), data);
|
||||||
if (rangeValue)
|
if (rangeValue)
|
||||||
assignExprValue(tok, rangeValue, data);
|
assignExprValue(tok, rangeValue, data);
|
||||||
}
|
}
|
||||||
@ -2015,7 +2031,7 @@ static ExprEngine::ValuePtr executeDeref(const Token *tok, Data &data)
|
|||||||
{
|
{
|
||||||
ExprEngine::ValuePtr pval = executeExpression(tok->astOperand1(), data);
|
ExprEngine::ValuePtr pval = executeExpression(tok->astOperand1(), data);
|
||||||
if (!pval) {
|
if (!pval) {
|
||||||
auto v = getValueRangeFromValueType(data.getNewSymbolName(), tok->valueType(), *data.settings);
|
auto v = getValueRangeFromValueType(tok->valueType(), data);
|
||||||
if (tok->astOperand1()->varId()) {
|
if (tok->astOperand1()->varId()) {
|
||||||
pval = std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), ExprEngine::ValuePtr(), v, true, false, false);
|
pval = std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), ExprEngine::ValuePtr(), v, true, false, false);
|
||||||
data.assignValue(tok->astOperand1(), tok->astOperand1()->varId(), pval);
|
data.assignValue(tok->astOperand1(), tok->astOperand1()->varId(), pval);
|
||||||
@ -2363,7 +2379,7 @@ static std::string execute(const Token *start, const Token *end, Data &data)
|
|||||||
arrayValue->assign(std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 0, ~0ULL), std::make_shared<ExprEngine::BailoutValue>());
|
arrayValue->assign(std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 0, ~0ULL), std::make_shared<ExprEngine::BailoutValue>());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
data.assignValue(tok2, varid, getValueRangeFromValueType(data.getNewSymbolName(), lhs->valueType(), *data.settings));
|
data.assignValue(tok2, varid, getValueRangeFromValueType(lhs->valueType(), data));
|
||||||
continue;
|
continue;
|
||||||
} else if (Token::Match(tok2, "++|--") && tok2->astOperand1() && tok2->astOperand1()->variable()) {
|
} else if (Token::Match(tok2, "++|--") && tok2->astOperand1() && tok2->astOperand1()->variable()) {
|
||||||
// give variable "any" value
|
// give variable "any" value
|
||||||
@ -2375,7 +2391,7 @@ static std::string execute(const Token *start, const Token *end, Data &data)
|
|||||||
auto oldValue = data.getValue(varid, nullptr, nullptr);
|
auto oldValue = data.getValue(varid, nullptr, nullptr);
|
||||||
if (oldValue && oldValue->type == ExprEngine::ValueType::UninitValue)
|
if (oldValue && oldValue->type == ExprEngine::ValueType::UninitValue)
|
||||||
call(data.callbacks, tok2, oldValue, &data);
|
call(data.callbacks, tok2, oldValue, &data);
|
||||||
data.assignValue(tok2, varid, getValueRangeFromValueType(data.getNewSymbolName(), vartok->valueType(), *data.settings));
|
data.assignValue(tok2, varid, getValueRangeFromValueType(vartok->valueType(), data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2456,7 +2472,7 @@ static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data)
|
|||||||
ValueType vt(*valueType);
|
ValueType vt(*valueType);
|
||||||
vt.pointer = 0;
|
vt.pointer = 0;
|
||||||
if (vt.constness & 1)
|
if (vt.constness & 1)
|
||||||
pointerValue = getValueRangeFromValueType(data.getNewSymbolName(), &vt, *data.settings);
|
pointerValue = getValueRangeFromValueType(&vt, data);
|
||||||
else
|
else
|
||||||
pointerValue = std::make_shared<ExprEngine::UninitValue>();
|
pointerValue = std::make_shared<ExprEngine::UninitValue>();
|
||||||
}
|
}
|
||||||
@ -2469,7 +2485,7 @@ static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data)
|
|||||||
if (var.isLocal() && !var.isStatic())
|
if (var.isLocal() && !var.isStatic())
|
||||||
value = std::make_shared<ExprEngine::UninitValue>();
|
value = std::make_shared<ExprEngine::UninitValue>();
|
||||||
else
|
else
|
||||||
value = getValueRangeFromValueType(data.getNewSymbolName(), valueType, *data.settings);
|
value = getValueRangeFromValueType(valueType, data);
|
||||||
data.addConstraints(value, var.nameToken());
|
data.addConstraints(value, var.nameToken());
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -2480,19 +2496,7 @@ static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data)
|
|||||||
auto size = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 1, ~0UL);
|
auto size = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 1, ~0UL);
|
||||||
return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), size, structValue, true, true, false);
|
return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), size, structValue, true, true, false);
|
||||||
}
|
}
|
||||||
if (valueType->container) {
|
return getValueRangeFromValueType(valueType, data);
|
||||||
ExprEngine::ValuePtr value;
|
|
||||||
if (valueType->container->stdStringLike)
|
|
||||||
value = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), -128, 127);
|
|
||||||
else if (valueType->containerTypeToken) {
|
|
||||||
ValueType vt = ValueType::parseDecl(valueType->containerTypeToken, data.settings);
|
|
||||||
value = getValueRangeFromValueType(data.getNewSymbolName(), &vt, *data.settings);
|
|
||||||
} else
|
|
||||||
return ExprEngine::ValuePtr();
|
|
||||||
auto bufferSize = std::make_shared<ExprEngine::IntRange>(data.getNewSymbolName(), 0, ~0U);
|
|
||||||
return std::make_shared<ExprEngine::ArrayValue>(data.getNewSymbolName(), bufferSize, value, false, false, false);
|
|
||||||
}
|
|
||||||
return ExprEngine::ValuePtr();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExprEngine::executeFunction(const Scope *functionScope, ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings, const std::vector<ExprEngine::Callback> &callbacks, std::ostream &report)
|
void ExprEngine::executeFunction(const Scope *functionScope, ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings, const std::vector<ExprEngine::Callback> &callbacks, std::ostream &report)
|
||||||
|
@ -47,6 +47,7 @@ private:
|
|||||||
TEST_CASE(expr6);
|
TEST_CASE(expr6);
|
||||||
TEST_CASE(expr7);
|
TEST_CASE(expr7);
|
||||||
TEST_CASE(expr8);
|
TEST_CASE(expr8);
|
||||||
|
TEST_CASE(expr9);
|
||||||
TEST_CASE(exprAssign1);
|
TEST_CASE(exprAssign1);
|
||||||
TEST_CASE(exprAssign2); // Truncation
|
TEST_CASE(exprAssign2); // Truncation
|
||||||
|
|
||||||
@ -213,18 +214,20 @@ private:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string trackExecution(const char code[]) {
|
std::string trackExecution(const char code[], Settings *settings = nullptr) {
|
||||||
Settings settings;
|
Settings s;
|
||||||
settings.bugHunting = true;
|
if (!settings)
|
||||||
settings.debugBugHunting = true;
|
settings = &s;
|
||||||
settings.platform(cppcheck::Platform::Unix64);
|
settings->bugHunting = true;
|
||||||
settings.library.smartPointers.insert("std::shared_ptr");
|
settings->debugBugHunting = true;
|
||||||
Tokenizer tokenizer(&settings, this);
|
settings->platform(cppcheck::Platform::Unix64);
|
||||||
|
settings->library.smartPointers.insert("std::shared_ptr");
|
||||||
|
Tokenizer tokenizer(settings, this);
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
std::vector<ExprEngine::Callback> callbacks;
|
std::vector<ExprEngine::Callback> callbacks;
|
||||||
std::ostringstream ret;
|
std::ostringstream ret;
|
||||||
ExprEngine::executeAllFunctions(this, &tokenizer, &settings, callbacks, ret);
|
ExprEngine::executeAllFunctions(this, &tokenizer, settings, callbacks, ret);
|
||||||
return ret.str();
|
return ret.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,6 +322,22 @@ private:
|
|||||||
expr(code, "==");
|
expr(code, "==");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void expr9() {
|
||||||
|
Settings settings;
|
||||||
|
LOAD_LIB_2(settings.library, "std.cfg");
|
||||||
|
|
||||||
|
ASSERT_EQUALS("1:26: $3=0:ffffffff\n"
|
||||||
|
"1:26: $2=-128:127\n"
|
||||||
|
"1:27: { s=($4,[$3],[:]=$2)}\n",
|
||||||
|
trackExecution("void foo() { std::string s; }", &settings));
|
||||||
|
|
||||||
|
|
||||||
|
ASSERT_EQUALS("1:52: $3=0:ffffffff\n"
|
||||||
|
"1:52: $2=-128:127\n"
|
||||||
|
"1:66: { s=($4,[$3],[:]=$2)}\n",
|
||||||
|
trackExecution("std::string getName(int); void foo() { std::string s = getName(1); }", &settings));
|
||||||
|
}
|
||||||
|
|
||||||
void exprAssign1() {
|
void exprAssign1() {
|
||||||
ASSERT_EQUALS("($1)+(1)", getRange("void f(unsigned char a) { a += 1; }", "a+=1"));
|
ASSERT_EQUALS("($1)+(1)", getRange("void f(unsigned char a) { a += 1; }", "a+=1"));
|
||||||
}
|
}
|
||||||
@ -417,8 +436,8 @@ private:
|
|||||||
" x==3;\n"
|
" x==3;\n"
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
ASSERT_EQUALS("(and (>= $2 0) (<= $2 65535))\n"
|
ASSERT_EQUALS("(and (>= $1 0) (<= $1 65535))\n"
|
||||||
"(= $2 3)\n"
|
"(= $1 3)\n"
|
||||||
"z3::sat\n",
|
"z3::sat\n",
|
||||||
expr(code, "=="));
|
expr(code, "=="));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user