Support getters in trusted mode too

This commit is contained in:
Leo Alt 2021-10-20 12:52:30 +02:00
parent 4b1cfcd54e
commit 9c7e1bbbb5
5 changed files with 34 additions and 19 deletions

View File

@ -130,7 +130,7 @@ bool BMC::shouldInlineFunctionCall(
FunctionType const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type);
if (funType.kind() == FunctionType::Kind::External)
return isTrustedExternalCall(&_funCall.expression());
return isExternalCallToThis(&_funCall.expression());
else if (funType.kind() != FunctionType::Kind::Internal)
return false;
@ -567,7 +567,7 @@ void BMC::internalOrExternalFunctionCall(FunctionCall const& _funCall)
auto const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type);
if (shouldInlineFunctionCall(_funCall, currentScopeContract(), m_currentContract))
inlineFunctionCall(_funCall);
else if (isPublicGetter(_funCall.expression()))
else if (publicGetter(_funCall.expression()))
{
// Do nothing here.
// The processing happens in SMT Encoder, but we need to prevent the resetting of the state variables.

View File

@ -736,6 +736,18 @@ void CHC::visitAssert(FunctionCall const& _funCall)
verificationTargetEncountered(&_funCall, VerificationTargetType::Assert, errorCondition);
}
void CHC::visitPublicGetter(FunctionCall const& _funCall)
{
createExpr(_funCall);
if (encodeExternalCallsAsTrusted())
{
auto const& access = dynamic_cast<MemberAccess const&>(_funCall.expression());
auto const& contractType = dynamic_cast<ContractType const&>(*access.expression().annotation().type);
state().readStateVars(contractType.contractDefinition(), expr(access.expression()));
}
SMTEncoder::visitPublicGetter(_funCall);
}
void CHC::visitAddMulMod(FunctionCall const& _funCall)
{
solAssert(_funCall.arguments().at(2), "");
@ -887,7 +899,7 @@ void CHC::externalFunctionCall(FunctionCall const& _funCall)
if (
encodeExternalCallsAsTrusted() ||
isTrustedExternalCall(callExpr)
isExternalCallToThis(callExpr)
)
{
externalFunctionCallToTrustedCode(_funCall);
@ -957,6 +969,9 @@ void CHC::externalFunctionCall(FunctionCall const& _funCall)
void CHC::externalFunctionCallToTrustedCode(FunctionCall const& _funCall)
{
if (publicGetter(_funCall.expression()))
visitPublicGetter(_funCall);
solAssert(m_currentContract, "");
auto [callExpr, callOptions] = functionCallExpression(_funCall);

View File

@ -110,6 +110,7 @@ private:
void popInlineFrame(CallableDeclaration const& _callable) override;
void visitAssert(FunctionCall const& _funCall);
void visitPublicGetter(FunctionCall const& _funCall) override;
void visitAddMulMod(FunctionCall const& _funCall) override;
void visitDeployment(FunctionCall const& _funCall);
void internalFunctionCall(FunctionCall const& _funCall);

View File

@ -646,7 +646,7 @@ void SMTEncoder::endVisit(FunctionCall const& _funCall)
visitGasLeft(_funCall);
break;
case FunctionType::Kind::External:
if (isPublicGetter(_funCall.expression()))
if (publicGetter(_funCall.expression()))
visitPublicGetter(_funCall);
break;
case FunctionType::Kind::ABIDecode:
@ -995,9 +995,8 @@ vector<string> structGetterReturnedMembers(StructType const& _structType)
void SMTEncoder::visitPublicGetter(FunctionCall const& _funCall)
{
MemberAccess const& access = dynamic_cast<MemberAccess const&>(_funCall.expression());
auto var = dynamic_cast<VariableDeclaration const*>(access.annotation().referencedDeclaration);
solAssert(var, "");
auto var = publicGetter(_funCall.expression());
solAssert(var && var->isStateVariable(), "");
solAssert(m_context.knownExpression(_funCall), "");
auto paramExpectedTypes = replaceUserTypes(FunctionType(*var).parameterTypes());
auto actualArguments = _funCall.arguments();
@ -2800,16 +2799,13 @@ smtutil::Expression SMTEncoder::contractAddressValue(FunctionCall const& _f)
solAssert(false, "Unreachable!");
}
bool SMTEncoder::isPublicGetter(Expression const& _expr) {
if (!isTrustedExternalCall(&_expr))
return false;
auto varDecl = dynamic_cast<VariableDeclaration const*>(
dynamic_cast<MemberAccess const&>(_expr).annotation().referencedDeclaration
);
return varDecl != nullptr;
VariableDeclaration const* SMTEncoder::publicGetter(Expression const& _expr) const {
if (auto memberAccess = dynamic_cast<MemberAccess const*>(&_expr))
return dynamic_cast<VariableDeclaration const*>(memberAccess->annotation().referencedDeclaration);
return nullptr;
}
bool SMTEncoder::isTrustedExternalCall(Expression const* _expr) {
bool SMTEncoder::isExternalCallToThis(Expression const* _expr) {
auto memberAccess = dynamic_cast<MemberAccess const*>(_expr);
if (!memberAccess)
return false;

View File

@ -219,7 +219,7 @@ protected:
void visitTypeConversion(FunctionCall const& _funCall);
void visitStructConstructorCall(FunctionCall const& _funCall);
void visitFunctionIdentifier(Identifier const& _identifier);
void visitPublicGetter(FunctionCall const& _funCall);
virtual void visitPublicGetter(FunctionCall const& _funCall);
/// @returns true if @param _contract is set for analysis in the settings
/// and it is not abstract.
@ -227,7 +227,10 @@ protected:
/// @returns true if @param _source is set for analysis in the settings.
bool shouldAnalyze(SourceUnit const& _source) const;
bool isPublicGetter(Expression const& _expr);
/// @returns the state variable returned by a public getter if
/// @a _expr is a call to a public getter,
/// otherwise nullptr.
VariableDeclaration const* publicGetter(Expression const& _expr) const;
smtutil::Expression contractAddressValue(FunctionCall const& _f);
@ -394,9 +397,9 @@ protected:
/// otherwise nullptr.
MemberAccess const* isEmptyPush(Expression const& _expr) const;
/// @returns true if the given identifier is a contract which is known and trusted.
/// @returns true if the given expression is `this`.
/// This means we don't have to abstract away effects of external function calls to this contract.
static bool isTrustedExternalCall(Expression const* _expr);
static bool isExternalCallToThis(Expression const* _expr);
/// Creates symbolic expressions for the returned values
/// and set them as the components of the symbolic tuple.