| 1490 | } |
| 1491 | |
| 1492 | void CHC::defineExternalFunctionInterface(FunctionDefinition const& _function, ContractDefinition const& _contract) |
| 1493 | { |
| 1494 | // Create a rule that represents an external call to this function. |
| 1495 | // This contains more things than the function body itself, |
| 1496 | // such as balance updates because of ``msg.value``. |
| 1497 | auto functionEntryBlock = createBlock(&_function, PredicateType::FunctionBlock); |
| 1498 | auto functionPred = predicate(*functionEntryBlock); |
| 1499 | addRule(functionPred, functionPred.name); |
| 1500 | setCurrentBlock(*functionEntryBlock); |
| 1501 | |
| 1502 | m_context.addAssertion(initialConstraints(_contract, &_function)); |
| 1503 | m_context.addAssertion(state().txTypeConstraints() && state().txFunctionConstraints(_function)); |
| 1504 | |
| 1505 | // The contract may have received funds through a selfdestruct or |
| 1506 | // block.coinbase, which do not trigger calls into the contract. |
| 1507 | // So the only constraint we can add here is that the balance of |
| 1508 | // the contract grows by at least `msg.value`. |
| 1509 | SymbolicIntVariable k{TypeProvider::uint256(), TypeProvider::uint256(), "funds_" + std::to_string(m_context.newUniqueId()), m_context}; |
| 1510 | m_context.addAssertion(k.currentValue() >= state().txMember("msg.value")); |
| 1511 | // Assume that address(this).balance cannot overflow. |
| 1512 | m_context.addAssertion(smt::symbolicUnknownConstraints(state().balance(state().thisAddress()) + k.currentValue(), TypeProvider::uint256())); |
| 1513 | state().addBalance(state().thisAddress(), k.currentValue()); |
| 1514 | |
| 1515 | if (encodeExternalCallsAsTrusted()) |
| 1516 | { |
| 1517 | // If the contract has state variables that are addresses to other contracts, |
| 1518 | // we need to encode the fact that those contracts may have been called in between |
| 1519 | // transactions to _contract. |
| 1520 | // |
| 1521 | // We do that by adding nondet_interface constraints for those contracts, |
| 1522 | // in the last line of this if block. |
| 1523 | // |
| 1524 | // If there are state variables of container types like structs or arrays |
| 1525 | // that indirectly contain contract types, we havoc the state for simplicity, |
| 1526 | // in the first part of this block. |
| 1527 | // TODO: This could actually be supported. |
| 1528 | // For structs: simply collect the SMT expressions of all the indirect contract type members. |
| 1529 | // For arrays: more involved, needs to traverse the array symbolically and do the same for each contract. |
| 1530 | // For mappings: way more complicated if the element type is a contract. |
| 1531 | auto hasContractOrAddressSubType = [&](VariableDeclaration const* _var) -> bool { |
| 1532 | bool foundContract = false; |
| 1533 | solidity::util::BreadthFirstSearch<Type const*> bfs{{_var->type()}}; |
| 1534 | bfs.run([&](auto _type, auto&& _addChild) { |
| 1535 | if ( |
| 1536 | _type->category() == Type::Category::Address || |
| 1537 | _type->category() == Type::Category::Contract |
| 1538 | ) |
| 1539 | { |
| 1540 | foundContract = true; |
| 1541 | bfs.abort(); |
| 1542 | } |
| 1543 | if (auto const* mapType = dynamic_cast<MappingType const*>(_type)) |
| 1544 | _addChild(mapType->valueType()); |
| 1545 | else if (auto const* arrayType = dynamic_cast<ArrayType const*>(_type)) |
| 1546 | _addChild(arrayType->baseType()); |
| 1547 | else if (auto const* structType = dynamic_cast<StructType const*>(_type)) |
| 1548 | for (auto const& member: structType->nativeMembers(nullptr)) |
| 1549 | _addChild(member.type); |
nothing calls this directly
no test coverage detected