Skip to content

Commit b53eba3

Browse files
authored
Merge pull request #15880 from ethereum/smt-fix-contract-selection
SMTChecker: Fix analysis for selected contracts
2 parents 9620f4f + 25463c5 commit b53eba3

File tree

18 files changed

+94
-128
lines changed

18 files changed

+94
-128
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Compiler Features:
77

88

99
Bugfixes:
10+
* SMTChecker: Fix incorrect analysis when only a subset of contracts is selected with `--model-checker-contracts`.
1011

1112

1213
### 0.8.29 (2025-03-12)

libsolidity/formal/BMC.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1068,7 +1068,7 @@ void BMC::addVerificationTarget(
10681068
Expression const* _expression
10691069
)
10701070
{
1071-
if (!m_settings.targets.has(_type) || (m_currentContract && !shouldAnalyze(*m_currentContract)))
1071+
if (!m_settings.targets.has(_type) || (m_currentContract && !shouldAnalyzeVerificationTargetsFor(*m_currentContract)))
10721072
return;
10731073

10741074
BMCVerificationTarget target{

libsolidity/formal/CHC.cpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ void CHC::analyze(SourceUnit const& _source)
8989
" If you wish to use Eldarica, please enable Eldarica only."
9090
);
9191

92-
if (!shouldAnalyze(_source))
92+
if (!shouldAnalyzeVerificationTargetsFor(_source))
9393
return;
9494

9595
resetSourceAnalysis();
@@ -131,7 +131,7 @@ std::vector<std::string> CHC::unhandledQueries() const
131131

132132
bool CHC::visit(ContractDefinition const& _contract)
133133
{
134-
if (!shouldAnalyze(_contract))
134+
if (!shouldEncode(_contract))
135135
return false;
136136

137137
// Raises UnimplementedFeatureError in the presence of transient storage variables
@@ -152,7 +152,7 @@ bool CHC::visit(ContractDefinition const& _contract)
152152

153153
void CHC::endVisit(ContractDefinition const& _contract)
154154
{
155-
if (!shouldAnalyze(_contract))
155+
if (!shouldEncode(_contract))
156156
return;
157157

158158
for (auto base: _contract.annotation().linearizedBaseContracts)
@@ -239,15 +239,14 @@ void CHC::endVisit(ContractDefinition const& _contract)
239239
setCurrentBlock(*m_constructorSummaries.at(&_contract));
240240

241241
solAssert(&_contract == m_currentContract, "");
242-
if (shouldAnalyze(_contract))
243-
{
244-
auto constructor = _contract.constructor();
245-
auto txConstraints = state().txTypeConstraints();
246-
if (!constructor || !constructor->isPayable())
247-
txConstraints = txConstraints && state().txNonPayableConstraint();
242+
smtAssert(shouldEncode(_contract));
243+
auto constructor = _contract.constructor();
244+
auto txConstraints = state().txTypeConstraints();
245+
if (!constructor || !constructor->isPayable())
246+
txConstraints = txConstraints && state().txNonPayableConstraint();
247+
connectBlocks(m_currentBlock, interface(), txConstraints && errorFlag().currentValue() == 0);
248+
if (shouldAnalyzeVerificationTargetsFor(_contract))
248249
m_queryPlaceholders[&_contract].push_back({txConstraints, errorFlag().currentValue(), m_currentBlock});
249-
connectBlocks(m_currentBlock, interface(), txConstraints && errorFlag().currentValue() == 0);
250-
}
251250

252251
solAssert(m_scopes.back() == &_contract, "");
253252
m_scopes.pop_back();
@@ -338,7 +337,7 @@ void CHC::endVisit(FunctionDefinition const& _function)
338337
!_function.isConstructor() &&
339338
_function.isPublic() &&
340339
contractFunctions(*m_currentContract).count(&_function) &&
341-
shouldAnalyze(*m_currentContract)
340+
shouldEncode(*m_currentContract)
342341
)
343342
{
344343
defineExternalFunctionInterface(_function, *m_currentContract);
@@ -349,8 +348,9 @@ void CHC::endVisit(FunctionDefinition const& _function)
349348
auto ifacePre = smt::interfacePre(*m_interfaces.at(m_currentContract), *m_currentContract, m_context);
350349
auto sum = externalSummary(_function);
351350

352-
m_queryPlaceholders[&_function].push_back({sum, errorFlag().currentValue(), ifacePre});
353351
connectBlocks(ifacePre, interface(), sum && errorFlag().currentValue() == 0);
352+
if (shouldAnalyzeVerificationTargetsFor(*m_currentContract))
353+
m_queryPlaceholders[&_function].push_back({sum, errorFlag().currentValue(), ifacePre});
354354
}
355355

356356
m_currentFunction = nullptr;

libsolidity/formal/ModelCheckerSettings.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ std::optional<ModelCheckerContracts> ModelCheckerContracts::fromString(std::stri
123123
{
124124
auto&& names = sourceContract | ranges::views::split(':') | ranges::to<std::vector<std::string>>();
125125
if (names.size() != 2 || names.at(0).empty() || names.at(1).empty())
126-
return {};
126+
return std::nullopt;
127127
chosen[names.at(0)].insert(names.at(1));
128128
}
129129

libsolidity/formal/SMTEncoder.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,19 +1092,24 @@ void SMTEncoder::visitPublicGetter(FunctionCall const& _funCall)
10921092
}
10931093
}
10941094

1095-
bool SMTEncoder::shouldAnalyze(SourceUnit const& _source) const
1095+
bool SMTEncoder::shouldEncode(ContractDefinition const& _contract) const
1096+
{
1097+
return _contract.canBeDeployed();
1098+
}
1099+
1100+
bool SMTEncoder::shouldAnalyzeVerificationTargetsFor(SourceUnit const& _source) const
10961101
{
10971102
return m_settings.contracts.isDefault() ||
10981103
m_settings.contracts.has(*_source.annotation().path);
10991104
}
11001105

1101-
bool SMTEncoder::shouldAnalyze(ContractDefinition const& _contract) const
1106+
bool SMTEncoder::shouldAnalyzeVerificationTargetsFor(ContractDefinition const& _contract) const
11021107
{
1103-
if (!_contract.canBeDeployed())
1108+
if (!shouldEncode(_contract))
11041109
return false;
11051110

11061111
return m_settings.contracts.isDefault() ||
1107-
m_settings.contracts.has(_contract.sourceUnitName());
1112+
m_settings.contracts.has(_contract.sourceUnitName(), _contract.name());
11081113
}
11091114

11101115
void SMTEncoder::visitTypeConversion(FunctionCall const& _funCall)

libsolidity/formal/SMTEncoder.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,12 @@ class SMTEncoder: public ASTConstVisitor
238238
void visitFunctionIdentifier(Identifier const& _identifier);
239239
virtual void visitPublicGetter(FunctionCall const& _funCall);
240240

241-
/// @returns true if @param _contract is set for analysis in the settings
242-
/// and it is not abstract.
243-
bool shouldAnalyze(ContractDefinition const& _contract) const;
244-
/// @returns true if @param _source is set for analysis in the settings.
245-
bool shouldAnalyze(SourceUnit const& _source) const;
241+
/// @returns true if symbolic representation of @param _contract is required for verification
242+
bool shouldEncode(ContractDefinition const& _contract) const;
243+
/// @returns true if the verification targets of @param _contract are actually selected for verification
244+
bool shouldAnalyzeVerificationTargetsFor(ContractDefinition const& _contract) const;
245+
/// @returns true if we should descend into @param _source to look for contracts that should be verified
246+
bool shouldAnalyzeVerificationTargetsFor(SourceUnit const& _source) const;
246247

247248
/// @returns the state variable returned by a public getter if
248249
/// @a _expr is a call to a public getter,
Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1 @@
11
Warning: Requested contract "C" does not exist in source "model_checker_contracts_inexistent_contract/input.sol".
2-
3-
Warning: CHC: Assertion violation happens here.
4-
Counterexample:
5-
6-
x = 0
7-
8-
Transaction trace:
9-
B.constructor()
10-
B.f(0)
11-
--> model_checker_contracts_inexistent_contract/input.sol:5:3:
12-
|
13-
5 | assert(x > 0);
14-
| ^^^^^^^^^^^^^
15-
16-
Warning: CHC: Assertion violation happens here.
17-
Counterexample:
18-
19-
y = 0
20-
21-
Transaction trace:
22-
A.constructor()
23-
A.g(0)
24-
--> model_checker_contracts_inexistent_contract/input.sol:10:3:
25-
|
26-
10 | assert(y > 0);
27-
| ^^^^^^^^^^^^^

test/cmdlineTests/model_checker_contracts_only_one/err

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Counterexample:
44
x = 0
55

66
Transaction trace:
7-
B.constructor()
7+
A.constructor()
88
B.f(0)
99
--> model_checker_contracts_only_one/input.sol:5:3:
1010
|

test/cmdlineTests/standard_model_checker_contracts_inexistent_contract/output.json

Lines changed: 0 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -9,72 +9,6 @@
99
"message": "Requested contract \"C\" does not exist in source \"Source\".",
1010
"severity": "warning",
1111
"type": "Warning"
12-
},
13-
{
14-
"component": "general",
15-
"errorCode": "6328",
16-
"formattedMessage": "Warning: CHC: Assertion violation happens here.
17-
Counterexample:
18-
19-
y = 0
20-
21-
Transaction trace:
22-
B.constructor()
23-
B.g(0)
24-
--> Source:5:7:
25-
|
26-
5 | \t\t\t\t\t\tassert(y > 0);
27-
| \t\t\t\t\t\t^^^^^^^^^^^^^
28-
29-
",
30-
"message": "CHC: Assertion violation happens here.
31-
Counterexample:
32-
33-
y = 0
34-
35-
Transaction trace:
36-
B.constructor()
37-
B.g(0)",
38-
"severity": "warning",
39-
"sourceLocation": {
40-
"end": 137,
41-
"file": "Source",
42-
"start": 124
43-
},
44-
"type": "Warning"
45-
},
46-
{
47-
"component": "general",
48-
"errorCode": "6328",
49-
"formattedMessage": "Warning: CHC: Assertion violation happens here.
50-
Counterexample:
51-
52-
x = 0
53-
54-
Transaction trace:
55-
A.constructor()
56-
A.f(0)
57-
--> Source:10:7:
58-
|
59-
10 | \t\t\t\t\t\tassert(x > 0);
60-
| \t\t\t\t\t\t^^^^^^^^^^^^^
61-
62-
",
63-
"message": "CHC: Assertion violation happens here.
64-
Counterexample:
65-
66-
x = 0
67-
68-
Transaction trace:
69-
A.constructor()
70-
A.f(0)",
71-
"severity": "warning",
72-
"sourceLocation": {
73-
"end": 231,
74-
"file": "Source",
75-
"start": 218
76-
},
77-
"type": "Warning"
7812
}
7913
],
8014
"sources": {

test/cmdlineTests/standard_model_checker_contracts_multi_source/output.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Counterexample:
99
y = 0
1010

1111
Transaction trace:
12-
B.constructor()
12+
A.constructor()
1313
B.g(0)
1414
--> Source:5:7:
1515
|
@@ -23,7 +23,7 @@ Counterexample:
2323
y = 0
2424

2525
Transaction trace:
26-
B.constructor()
26+
A.constructor()
2727
B.g(0)",
2828
"severity": "warning",
2929
"sourceLocation": {

0 commit comments

Comments
 (0)