Merge pull request #6665 from ethereum/smt_inline_external_this

[SMTChecker] Inline external function calls to `this`
This commit is contained in:
chriseth 2019-05-09 19:09:08 +02:00 committed by GitHub
commit 89700dbcff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 108 additions and 6 deletions

View File

@ -8,6 +8,7 @@ Compiler Features:
* SMTChecker: Support inherited state variables. * SMTChecker: Support inherited state variables.
* SMTChecker: Support tuples and function calls with multiple return values. * SMTChecker: Support tuples and function calls with multiple return values.
* SMTChecker: Support ``delete``. * SMTChecker: Support ``delete``.
* SMTChecker: Inline external function calls to ``this``.
* Assembler: Encode the compiler version in the deployed bytecode. * Assembler: Encode the compiler version in the deployed bytecode.

View File

@ -665,8 +665,6 @@ void SMTChecker::endVisit(FunctionCall const& _funCall)
visitGasLeft(_funCall); visitGasLeft(_funCall);
break; break;
case FunctionType::Kind::Internal: case FunctionType::Kind::Internal:
inlineFunctionCall(_funCall);
break;
case FunctionType::Kind::External: case FunctionType::Kind::External:
case FunctionType::Kind::DelegateCall: case FunctionType::Kind::DelegateCall:
case FunctionType::Kind::BareCall: case FunctionType::Kind::BareCall:
@ -674,9 +672,7 @@ void SMTChecker::endVisit(FunctionCall const& _funCall)
case FunctionType::Kind::BareDelegateCall: case FunctionType::Kind::BareDelegateCall:
case FunctionType::Kind::BareStaticCall: case FunctionType::Kind::BareStaticCall:
case FunctionType::Kind::Creation: case FunctionType::Kind::Creation:
m_externalFunctionCallHappened = true; internalOrExternalFunctionCall(_funCall);
resetStateVariables();
resetStorageReferences();
break; break;
case FunctionType::Kind::KECCAK256: case FunctionType::Kind::KECCAK256:
case FunctionType::Kind::ECRecover: case FunctionType::Kind::ECRecover:
@ -804,6 +800,25 @@ void SMTChecker::inlineFunctionCall(FunctionCall const& _funCall)
} }
} }
void SMTChecker::internalOrExternalFunctionCall(FunctionCall const& _funCall)
{
auto funDef = inlinedFunctionCallToDefinition(_funCall);
auto const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type);
if (funDef)
inlineFunctionCall(_funCall);
else if (funType.kind() == FunctionType::Kind::Internal)
m_errorReporter.warning(
_funCall.location(),
"Assertion checker does not yet implement this type of function call."
);
else
{
m_externalFunctionCallHappened = true;
resetStateVariables();
resetStorageReferences();
}
}
void SMTChecker::abstractFunctionCall(FunctionCall const& _funCall) void SMTChecker::abstractFunctionCall(FunctionCall const& _funCall)
{ {
vector<smt::Expression> smtArguments; vector<smt::Expression> smtArguments;
@ -1930,7 +1945,21 @@ FunctionDefinition const* SMTChecker::inlinedFunctionCallToDefinition(FunctionCa
return nullptr; return nullptr;
FunctionType const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type); FunctionType const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type);
if (funType.kind() != FunctionType::Kind::Internal) if (funType.kind() == FunctionType::Kind::External)
{
auto memberAccess = dynamic_cast<MemberAccess const*>(&_funCall.expression());
auto identifier = memberAccess ?
dynamic_cast<Identifier const*>(&memberAccess->expression()) :
nullptr;
if (!(
identifier &&
identifier->name() == "this" &&
identifier->annotation().referencedDeclaration &&
dynamic_cast<MagicVariableDeclaration const*>(identifier->annotation().referencedDeclaration)
))
return nullptr;
}
else if (funType.kind() != FunctionType::Kind::Internal)
return nullptr; return nullptr;
FunctionDefinition const* funDef = nullptr; FunctionDefinition const* funDef = nullptr;

View File

@ -115,6 +115,9 @@ private:
void inlineFunctionCall(FunctionCall const& _funCall); void inlineFunctionCall(FunctionCall const& _funCall);
/// Creates an uninterpreted function call. /// Creates an uninterpreted function call.
void abstractFunctionCall(FunctionCall const& _funCall); void abstractFunctionCall(FunctionCall const& _funCall);
/// Inlines if the function call is internal or external to `this`.
/// Erases knowledge about state variables if external.
void internalOrExternalFunctionCall(FunctionCall const& _funCall);
void visitFunctionIdentifier(Identifier const& _identifier); void visitFunctionIdentifier(Identifier const& _identifier);
/// Encodes a modifier or function body according to the modifier /// Encodes a modifier or function body according to the modifier

View File

@ -9,4 +9,5 @@ contract C {
} }
} }
// ---- // ----
// Warning: (99-107): Assertion checker does not support recursive function calls.
// Warning: (141-144): Assertion checker does not support recursive function calls. // Warning: (141-144): Assertion checker does not support recursive function calls.

View File

@ -0,0 +1,14 @@
pragma experimental SMTChecker;
contract C
{
uint x;
function f(uint y) public {
x = y;
}
function g(uint y) public {
require(y < 1000);
this.f(y);
assert(x < 1000);
}
}

View File

@ -0,0 +1,15 @@
pragma experimental SMTChecker;
contract C
{
uint x;
function f(uint y) public returns (uint) {
x = y;
return x;
}
function g(uint y) public {
require(y < 1000);
uint z = this.f(y);
assert(z < 1000);
}
}

View File

@ -0,0 +1,24 @@
pragma experimental SMTChecker;
contract C
{
uint public x;
C c;
function f(C _c) public {
c = _c;
}
function g() public {
C this = c;
x = 0;
this.h();
// State knowledge is erased.
// Function call is not inlined.
assert(x == 0);
}
function h() public {
x = 2;
}
}
// ----
// Warning: (160-166): This declaration shadows a builtin symbol.
// Warning: (268-282): Assertion violation happens here

View File

@ -0,0 +1,15 @@
pragma experimental SMTChecker;
contract C
{
uint public x;
function g() public {
x = 0;
this.h();
// Function call is inlined.
assert(x == 2);
}
function h() public {
x = 2;
}
}