Change settings.modelChecker.targets to take an array instead of string

This commit is contained in:
Leonardo Alt 2021-04-14 12:56:43 +02:00
parent 6ef7e39e46
commit e3abde43f5
41 changed files with 180 additions and 62 deletions

View File

@ -18,6 +18,7 @@ Compiler Features:
* SMTChecker: Report local variables in CHC counterexamples.
* SMTChecker: Report out of bounds index access for arrays and fixed bytes.
* Standard JSON: Model checker option ``settings.modelChecker.targets`` also accepts ``outOfBounds``.
* Standard JSON: Model checker option ``settings.modelChecker.targets`` takes an array of string targets instead of string of comma separated targets.
* Yul Optimizer: Added a new step FunctionSpecializer, that specializes a function with its literal arguments.
* Yul EVM Code Transform: Stack Optimization: Reuse slots of unused function arguments and defer allocating stack slots for return variables until after expression statements and assignments that do not reference them.
* NatSpec: Allow ``@notice`` tag on non-public state variables and local variable declarations. The documentation will only be part of the AST, under the field ``documentation``.

View File

@ -448,10 +448,13 @@ the JSON option ``settings.modelChecker.timeout=<time>``, where 0 means no timeo
Verification Targets
====================
The types of verification targets created by the SMTChecker can also be customized via
the CLI option ``--model-checker-target <targets>`` or the JSON option
``settings.modelChecker.targets=<targets>``, where ``<targets>`` is a no-space-comma-separated
list of one or more verification targets. The keywords that represent the targets are:
The types of verification targets created by the SMTChecker can also be
customized via the CLI option ``--model-checker-target <targets>`` or the JSON
option ``settings.modelChecker.targets=<targets>``.
In the CLI case, ``<targets>`` is a no-space-comma-separated list of one or
more verification targets, and an array of one or more targets as strings in
the JSON input.
The keywords that represent the targets are:
- Assertions: ``assert``.
- Arithmetic underflow: ``underflow``.
@ -461,8 +464,7 @@ list of one or more verification targets. The keywords that represent the target
- Popping an empty array: ``popEmptyArray``.
- Out of bounds array/fixed bytes index access: ``outOfBounds``.
- Insufficient funds for a transfer: ``balance``.
- All of the above: ``all``.
- None of the above: ``none``.
- All of the above: ``default`` (CLI only).
A common subset of targets might be, for example:
``--model-checker-targets assert,overflow``.

View File

@ -374,16 +374,16 @@ Input Description
"MyContract": [ "abi", "evm.bytecode.opcodes" ]
}
},
// The modelChecker object is experimental and subject to changes.
"modelChecker":
{
// Choose which model checker engine to use: all (default), bmc, chc, none.
"engine": "chc",
// Choose which targets should be checked: all (default), constantCondition,
// Choose which targets should be checked: constantCondition,
// underflow, overflow, divByZero, balance, assert, popEmptyArray, outOfBounds.
// If the option is not given all targets are checked by default.
// See the Formal Verification section for the targets description.
// Multiple targets can be selected at the same time, separated by a comma
// without spaces:
"targets": "underflow,overflow,assert",
"targets": ["underflow", "overflow", "assert"],
// Timeout for each SMT query in milliseconds.
// If this option is not given, the SMTChecker will use a deterministic
// resource limit by default.

View File

@ -26,22 +26,22 @@ using namespace ranges;
using namespace solidity;
using namespace solidity::frontend;
using TargetType = VerificationTargetType;
map<string, TargetType> const ModelCheckerTargets::targetStrings{
{"constantCondition", TargetType::ConstantCondition},
{"underflow", TargetType::Underflow},
{"overflow", TargetType::Overflow},
{"divByZero", TargetType::DivByZero},
{"balance", TargetType::Balance},
{"assert", TargetType::Assert},
{"popEmptyArray", TargetType::PopEmptyArray},
{"outOfBounds", TargetType::OutOfBounds}
};
std::optional<ModelCheckerTargets> ModelCheckerTargets::fromString(string const& _targets)
{
using TargetType = VerificationTargetType;
static map<string, TargetType> const targetStrings{
{"constantCondition", TargetType::ConstantCondition},
{"underflow", TargetType::Underflow},
{"overflow", TargetType::Overflow},
{"divByZero", TargetType::DivByZero},
{"balance", TargetType::Balance},
{"assert", TargetType::Assert},
{"popEmptyArray", TargetType::PopEmptyArray},
{"outOfBounds", TargetType::OutOfBounds}
};
set<TargetType> chosenTargets;
if (_targets == "all")
if (_targets == "default")
for (auto&& v: targetStrings | views::values)
chosenTargets.insert(v);
else
@ -54,3 +54,11 @@ std::optional<ModelCheckerTargets> ModelCheckerTargets::fromString(string const&
return ModelCheckerTargets{chosenTargets};
}
bool ModelCheckerTargets::setFromString(string const& _target)
{
if (!targetStrings.count(_target))
return false;
targets.insert(targetStrings.at(_target));
return true;
}

View File

@ -58,12 +58,18 @@ enum class VerificationTargetType { ConstantCondition, Underflow, Overflow, Unde
struct ModelCheckerTargets
{
static ModelCheckerTargets All() { return *fromString("all"); }
static ModelCheckerTargets None() { return {}; }
static ModelCheckerTargets All() { return *fromString("default"); }
static std::optional<ModelCheckerTargets> fromString(std::string const& _targets);
bool has(VerificationTargetType _type) const { return targets.count(_type); }
/// @returns true if the @p _target is valid,
/// and false otherwise.
bool setFromString(std::string const& _target);
static std::map<std::string, VerificationTargetType> const targetStrings;
std::set<VerificationTargetType> targets;
};

View File

@ -913,12 +913,23 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
if (modelCheckerSettings.isMember("targets"))
{
if (!modelCheckerSettings["targets"].isString())
return formatFatalError("JSONError", "settings.modelChecker.targets must be a string.");
std::optional<ModelCheckerTargets> targets = ModelCheckerTargets::fromString(modelCheckerSettings["targets"].asString());
if (!targets)
return formatFatalError("JSONError", "Invalid model checker targets requested.");
ret.modelCheckerSettings.targets = *targets;
auto const& targetsArray = modelCheckerSettings["targets"];
if (!targetsArray.isArray())
return formatFatalError("JSONError", "settings.modelChecker.targets must be an array.");
ModelCheckerTargets targets;
for (auto const& t: targetsArray)
{
if (!t.isString())
return formatFatalError("JSONError", "Every target in settings.modelChecker.targets must be a string.");
if (!targets.setFromString(t.asString()))
return formatFatalError("JSONError", "Invalid model checker targets requested.");
}
if (targets.targets.empty())
return formatFatalError("JSONError", "settings.modelChecker.targets must be a non-empty array.");
ret.modelCheckerSettings.targets = targets;
}
if (modelCheckerSettings.isMember("timeout"))

View File

@ -1060,7 +1060,7 @@ General Information)").c_str(),
)
(
g_strModelCheckerTargets.c_str(),
po::value<string>()->value_name("all,constantCondition,underflow,overflow,divByZero,balance,assert,popEmptyArray,outOfBounds")->default_value("all"),
po::value<string>()->value_name("default,constantCondition,underflow,overflow,divByZero,balance,assert,popEmptyArray,outOfBounds")->default_value("default"),
"Select model checker verification targets. "
"Multiple targets can be selected at the same time, separated by a comma "
"and no spaces."

View File

@ -1 +1 @@
--model-checker-engine all --model-checker-targets all
--model-checker-engine all --model-checker-targets default

View File

@ -1 +1 @@
--model-checker-engine bmc --model-checker-targets all
--model-checker-engine bmc --model-checker-targets default

View File

@ -1 +1 @@
--model-checker-engine chc --model-checker-targets all
--model-checker-engine chc --model-checker-targets default

View File

@ -23,8 +23,7 @@
{
"modelChecker":
{
"engine": "all",
"targets": "all"
"engine": "all"
}
}
}

View File

@ -23,8 +23,7 @@
{
"modelChecker":
{
"engine": "bmc",
"targets": "all"
"engine": "bmc"
}
}
}

View File

@ -23,8 +23,7 @@
{
"modelChecker":
{
"engine": "chc",
"targets": "all"
"engine": "chc"
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "bmc",
"targets": "assert"
"targets": ["assert"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "chc",
"targets": "assert"
"targets": ["assert"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "bmc",
"targets": "balance"
"targets": ["balance"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "chc",
"targets": "balance"
"targets": ["balance"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "bmc",
"targets": "constantCondition"
"targets": ["constantCondition"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "chc",
"targets": "constantCondition"
"targets": ["constantCondition"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "bmc",
"targets": "divByZero"
"targets": ["divByZero"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "chc",
"targets": "divByZero"
"targets": ["divByZero"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "all",
"targets": "aaa,bbb"
"targets": []
}
}
}

View File

@ -0,0 +1 @@
{"errors":[{"component":"general","formattedMessage":"settings.modelChecker.targets must be a non-empty array.","message":"settings.modelChecker.targets must be a non-empty array.","severity":"error","type":"JSONError"}]}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "bmc",
"targets": "outOfBounds"
"targets": ["outOfBounds"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "chc",
"targets": "outOfBounds"
"targets": ["outOfBounds"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "bmc",
"targets": "overflow"
"targets": ["overflow"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "chc",
"targets": "overflow"
"targets": ["overflow"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "bmc",
"targets": "popEmptyArray"
"targets": ["popEmptyArray"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "chc",
"targets": "popEmptyArray"
"targets": ["popEmptyArray"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "bmc",
"targets": "underflow"
"targets": ["underflow"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "chc",
"targets": "underflow"
"targets": ["underflow"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "bmc",
"targets": "underflow,overflow,assert"
"targets": ["underflow", "overflow", "assert"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "chc",
"targets": "underflow,overflow,assert"
"targets": ["underflow", "overflow", "assert"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "bmc",
"targets": "underflow,overflow"
"targets": ["underflow", "overflow"]
}
}
}

View File

@ -24,7 +24,7 @@
"modelChecker":
{
"engine": "chc",
"targets": "underflow,overflow"
"targets": ["underflow", "overflow"]
}
}
}

View File

@ -0,0 +1,30 @@
{
"language": "Solidity",
"sources":
{
"A":
{
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\n\ncontract test {
uint[] arr;
function f(address payable a, uint x) public {
require(x >= 0);
--x;
x + type(uint).max;
2 / x;
a.transfer(x);
assert(x > 0);
arr.pop();
arr[x];
}
}"
}
},
"settings":
{
"modelChecker":
{
"engine": "all",
"targets": [2]
}
}
}

View File

@ -0,0 +1 @@
{"errors":[{"component":"general","formattedMessage":"Every target in settings.modelChecker.targets must be a string.","message":"Every target in settings.modelChecker.targets must be a string.","severity":"error","type":"JSONError"}]}

View File

@ -0,0 +1,30 @@
{
"language": "Solidity",
"sources":
{
"A":
{
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\n\ncontract test {
uint[] arr;
function f(address payable a, uint x) public {
require(x >= 0);
--x;
x + type(uint).max;
2 / x;
a.transfer(x);
assert(x > 0);
arr.pop();
arr[x];
}
}"
}
},
"settings":
{
"modelChecker":
{
"engine": "all",
"targets": "assert"
}
}
}

View File

@ -0,0 +1 @@
{"errors":[{"component":"general","formattedMessage":"settings.modelChecker.targets must be an array.","message":"settings.modelChecker.targets must be an array.","severity":"error","type":"JSONError"}]}

View File

@ -0,0 +1,30 @@
{
"language": "Solidity",
"sources":
{
"A":
{
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\n\ncontract test {
uint[] arr;
function f(address payable a, uint x) public {
require(x >= 0);
--x;
x + type(uint).max;
2 / x;
a.transfer(x);
assert(x > 0);
arr.pop();
arr[x];
}
}"
}
},
"settings":
{
"modelChecker":
{
"engine": "all",
"targets": ["aaa", "bbb"]
}
}
}