Add gasleft constraint and use full member access name

This commit is contained in:
Leonardo Alt 2018-10-22 18:19:11 +02:00
parent b46b827c30
commit e2cf5f6ed9
7 changed files with 45 additions and 16 deletions

View File

@ -399,16 +399,21 @@ void SMTChecker::visitRequire(FunctionCall const& _funCall)
void SMTChecker::visitGasLeft(FunctionCall const& _funCall) void SMTChecker::visitGasLeft(FunctionCall const& _funCall)
{ {
string gasLeft = "gasleft"; string gasLeft = "gasleft()";
// We increase the variable index since gasleft changes // We increase the variable index since gasleft changes
// inside a tx. // inside a tx.
defineSpecialVariable(gasLeft, _funCall, true); defineSpecialVariable(gasLeft, _funCall, true);
m_specialVariables.at(gasLeft)->setUnknownValue(); auto const& symbolicVar = m_specialVariables.at(gasLeft);
unsigned index = symbolicVar->index();
// We set the current value to unknown anyway to add type constraints.
symbolicVar->setUnknownValue();
if (index > 0)
m_interface->addAssertion(symbolicVar->currentValue() <= symbolicVar->valueAtIndex(index - 1));
} }
void SMTChecker::visitBlockHash(FunctionCall const& _funCall) void SMTChecker::visitBlockHash(FunctionCall const& _funCall)
{ {
string blockHash = "blockhash"; string blockHash = "blockhash()";
// TODO Define blockhash as an uninterpreted function // TODO Define blockhash as an uninterpreted function
defineSpecialVariable(blockHash, _funCall); defineSpecialVariable(blockHash, _funCall);
} }
@ -480,11 +485,12 @@ void SMTChecker::endVisit(Identifier const& _identifier)
} }
else if (FunctionType const* fun = dynamic_cast<FunctionType const*>(_identifier.annotation().type.get())) else if (FunctionType const* fun = dynamic_cast<FunctionType const*>(_identifier.annotation().type.get()))
{ {
if (fun->kind() == FunctionType::Kind::Assert || if (
fun->kind() == FunctionType::Kind::Assert ||
fun->kind() == FunctionType::Kind::Require || fun->kind() == FunctionType::Kind::Require ||
fun->kind() == FunctionType::Kind::GasLeft || fun->kind() == FunctionType::Kind::GasLeft ||
fun->kind() == FunctionType::Kind::BlockHash fun->kind() == FunctionType::Kind::BlockHash
) )
return; return;
createExpr(_identifier); createExpr(_identifier);
} }
@ -541,7 +547,16 @@ bool SMTChecker::visit(MemberAccess const& _memberAccess)
solAssert(exprType, ""); solAssert(exprType, "");
if (exprType->category() == Type::Category::Magic) if (exprType->category() == Type::Category::Magic)
{ {
defineSpecialVariable(_memberAccess.memberName(), _memberAccess); auto identifier = dynamic_cast<Identifier const*>(&_memberAccess.expression());
string accessedName;
if (identifier)
accessedName = identifier->name();
else
m_errorReporter.warning(
_memberAccess.location(),
"Assertion checker does not yet support this expression."
);
defineSpecialVariable(accessedName + "." + _memberAccess.memberName(), _memberAccess);
return false; return false;
} }
else else

View File

@ -28,6 +28,6 @@ SSAVariable::SSAVariable()
void SSAVariable::resetIndex() void SSAVariable::resetIndex()
{ {
m_currentIndex = 0; m_currentIndex = 0;
m_nextFreeIndex.reset (new int); m_nextFreeIndex.reset (new unsigned);
*m_nextFreeIndex = 1; *m_nextFreeIndex = 1;
} }

View File

@ -34,19 +34,19 @@ public:
void resetIndex(); void resetIndex();
/// This function returns the current index of this SSA variable. /// This function returns the current index of this SSA variable.
int index() const { return m_currentIndex; } unsigned index() const { return m_currentIndex; }
int& index() { return m_currentIndex; } unsigned& index() { return m_currentIndex; }
int operator++() unsigned operator++()
{ {
return m_currentIndex = (*m_nextFreeIndex)++; return m_currentIndex = (*m_nextFreeIndex)++;
} }
private: private:
int m_currentIndex; unsigned m_currentIndex;
/// The next free index is a shared pointer because we want /// The next free index is a shared pointer because we want
/// the copy and the copied to share it. /// the copy and the copied to share it.
std::shared_ptr<int> m_nextFreeIndex; std::shared_ptr<unsigned> m_nextFreeIndex;
}; };
} }

View File

@ -35,7 +35,7 @@ SymbolicVariable::SymbolicVariable(
{ {
} }
string SymbolicVariable::uniqueSymbol(int _index) const string SymbolicVariable::uniqueSymbol(unsigned _index) const
{ {
return m_uniqueName + "_" + to_string(_index); return m_uniqueName + "_" + to_string(_index);
} }

View File

@ -59,8 +59,8 @@ public:
return currentValue(); return currentValue();
} }
int index() const { return m_ssa->index(); } unsigned index() const { return m_ssa->index(); }
int& index() { return m_ssa->index(); } unsigned& index() { return m_ssa->index(); }
/// Sets the var to the default value of its type. /// Sets the var to the default value of its type.
/// Inherited types must implement. /// Inherited types must implement.
@ -70,7 +70,7 @@ public:
virtual void setUnknownValue() {} virtual void setUnknownValue() {}
protected: protected:
std::string uniqueSymbol(int _index) const; std::string uniqueSymbol(unsigned _index) const;
TypePointer m_type = nullptr; TypePointer m_type = nullptr;
std::string m_uniqueName; std::string m_uniqueName;

View File

@ -0,0 +1,10 @@
pragma experimental SMTChecker;
contract C
{
function f(uint difficulty) public view {
assert(block.difficulty == difficulty);
}
}
// ----
// Warning: (91-129): Assertion violation happens here

View File

@ -4,7 +4,11 @@ contract C
{ {
function f() public view { function f() public view {
assert(gasleft() > 0); assert(gasleft() > 0);
uint g = gasleft();
assert(g < gasleft());
assert(g >= gasleft());
} }
} }
// ---- // ----
// Warning: (76-97): Assertion violation happens here // Warning: (76-97): Assertion violation happens here
// Warning: (123-144): Assertion violation happens here