@@ -169,7 +169,13 @@ void CHC::endVisit(ContractDefinition const& _contract)
169
169
smtutil::Expression zeroes (true );
170
170
for (auto var: stateVariablesIncludingInheritedAndPrivate (_contract))
171
171
zeroes = zeroes && currentValue (*var) == smt::zeroValue (var->type ());
172
- addRule (smtutil::Expression::implies (initialConstraints (_contract) && zeroes, predicate (entry)), entry.functor ().name );
172
+ // The contract's address might already have funds before deployment,
173
+ // so the balance must be at least `msg.value`, but not equals.
174
+ auto initialBalanceConstraint = state ().balance (state ().thisAddress ()) >= state ().txMember (" msg.value" );
175
+ addRule (smtutil::Expression::implies (
176
+ initialConstraints (_contract) && zeroes && initialBalanceConstraint,
177
+ predicate (entry)
178
+ ), entry.functor ().name );
173
179
setCurrentBlock (entry);
174
180
175
181
solAssert (!m_errorDest, " " );
@@ -315,11 +321,16 @@ void CHC::endVisit(FunctionDefinition const& _function)
315
321
shouldAnalyze (*m_currentContract)
316
322
)
317
323
{
318
- auto sum = summary (_function);
324
+ defineExternalFunctionInterface (_function, *m_currentContract);
325
+ setCurrentBlock (*m_interfaces.at (m_currentContract));
326
+
327
+ // Create the rule
328
+ // interface \land externalFunctionEntry => interface'
319
329
auto ifacePre = smt::interfacePre (*m_interfaces.at (m_currentContract), *m_currentContract, m_context);
320
- auto txConstraints = state ().txTypeConstraints () && state ().txFunctionConstraints (_function);
321
- m_queryPlaceholders[&_function].push_back ({txConstraints && sum, errorFlag ().currentValue (), ifacePre});
322
- connectBlocks (ifacePre, interface (), txConstraints && sum && errorFlag ().currentValue () == 0 );
330
+ auto sum = externalSummary (_function);
331
+
332
+ m_queryPlaceholders[&_function].push_back ({sum, errorFlag ().currentValue (), ifacePre});
333
+ connectBlocks (ifacePre, interface (), sum && errorFlag ().currentValue () == 0 );
323
334
}
324
335
325
336
m_currentFunction = nullptr ;
@@ -949,6 +960,7 @@ void CHC::resetSourceAnalysis()
949
960
m_queryPlaceholders.clear ();
950
961
m_callGraph.clear ();
951
962
m_summaries.clear ();
963
+ m_externalSummaries.clear ();
952
964
m_interfaces.clear ();
953
965
m_nondetInterfaces.clear ();
954
966
m_constructorSummaries.clear ();
@@ -1128,6 +1140,8 @@ void CHC::defineInterfacesAndSummaries(SourceUnit const& _source)
1128
1140
1129
1141
if (!function->isConstructor () && function->isPublic () && resolved.count (function))
1130
1142
{
1143
+ m_externalSummaries[contract].emplace (function, createSummaryBlock (*function, *contract));
1144
+
1131
1145
auto state1 = stateVariablesAtIndex (1 , *contract);
1132
1146
auto state2 = stateVariablesAtIndex (2 , *contract);
1133
1147
@@ -1144,12 +1158,41 @@ void CHC::defineInterfacesAndSummaries(SourceUnit const& _source)
1144
1158
applyMap (function->parameters (), [this ](auto _var) { return valueAtIndex (*_var, 1 ); }) +
1145
1159
applyMap (function->returnParameters (), [this ](auto _var) { return valueAtIndex (*_var, 1 ); });
1146
1160
1147
- connectBlocks (nondetPre, nondetPost, errorPre == 0 && (*m_summaries .at (contract).at (function))(args));
1161
+ connectBlocks (nondetPre, nondetPost, errorPre == 0 && (*m_externalSummaries .at (contract).at (function))(args));
1148
1162
}
1149
1163
}
1150
1164
}
1151
1165
}
1152
1166
1167
+ void CHC::defineExternalFunctionInterface (FunctionDefinition const & _function, ContractDefinition const & _contract)
1168
+ {
1169
+ // Create a rule that represents an external call to this function.
1170
+ // This contains more things than the function body itself,
1171
+ // such as balance updates because of ``msg.value``.
1172
+ auto functionEntryBlock = createBlock (&_function, PredicateType::FunctionBlock);
1173
+ auto functionPred = predicate (*functionEntryBlock);
1174
+ addRule (functionPred, functionPred.name );
1175
+ setCurrentBlock (*functionEntryBlock);
1176
+
1177
+ m_context.addAssertion (initialConstraints (_contract, &_function));
1178
+ m_context.addAssertion (state ().txTypeConstraints () && state ().txFunctionConstraints (_function));
1179
+
1180
+ // The contract may have received funds through a selfdestruct or
1181
+ // block.coinbase, which do not trigger calls into the contract.
1182
+ // So the only constraint we can add here is that the balance of
1183
+ // the contract grows by at least `msg.value`.
1184
+ SymbolicIntVariable k{TypeProvider::uint256 (), TypeProvider::uint256 (), " funds_" + to_string (m_context.newUniqueId ()), m_context};
1185
+ m_context.addAssertion (k.currentValue () >= state ().txMember (" msg.value" ));
1186
+ // Assume that address(this).balance cannot overflow.
1187
+ m_context.addAssertion (smt::symbolicUnknownConstraints (state ().balance (state ().thisAddress ()) + k.currentValue (), TypeProvider::uint256 ()));
1188
+ state ().addBalance (state ().thisAddress (), k.currentValue ());
1189
+
1190
+ errorFlag ().increaseIndex ();
1191
+ m_context.addAssertion (summaryCall (_function));
1192
+
1193
+ connectBlocks (functionPred, externalSummary (_function));
1194
+ }
1195
+
1153
1196
void CHC::defineContractInitializer (ContractDefinition const & _contract, ContractDefinition const & _contextContract)
1154
1197
{
1155
1198
m_contractInitializers[&_contextContract][&_contract] = createConstructorBlock (_contract, " contract_initializer" );
@@ -1220,12 +1263,34 @@ smtutil::Expression CHC::summary(FunctionDefinition const& _function, ContractDe
1220
1263
return smt::function (*m_summaries.at (&_contract).at (&_function), &_contract, m_context);
1221
1264
}
1222
1265
1266
+ smtutil::Expression CHC::summaryCall (FunctionDefinition const & _function, ContractDefinition const & _contract)
1267
+ {
1268
+ return smt::functionCall (*m_summaries.at (&_contract).at (&_function), &_contract, m_context);
1269
+ }
1270
+
1271
+ smtutil::Expression CHC::externalSummary (FunctionDefinition const & _function, ContractDefinition const & _contract)
1272
+ {
1273
+ return smt::function (*m_externalSummaries.at (&_contract).at (&_function), &_contract, m_context);
1274
+ }
1275
+
1223
1276
smtutil::Expression CHC::summary (FunctionDefinition const & _function)
1224
1277
{
1225
1278
solAssert (m_currentContract, " " );
1226
1279
return summary (_function, *m_currentContract);
1227
1280
}
1228
1281
1282
+ smtutil::Expression CHC::summaryCall (FunctionDefinition const & _function)
1283
+ {
1284
+ solAssert (m_currentContract, " " );
1285
+ return summaryCall (_function, *m_currentContract);
1286
+ }
1287
+
1288
+ smtutil::Expression CHC::externalSummary (FunctionDefinition const & _function)
1289
+ {
1290
+ solAssert (m_currentContract, " " );
1291
+ return externalSummary (_function, *m_currentContract);
1292
+ }
1293
+
1229
1294
Predicate const * CHC::createBlock (ASTNode const * _node, PredicateType _predType, string const & _prefix)
1230
1295
{
1231
1296
auto block = createSymbolicBlock (
0 commit comments