mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add gasleft constraint and use full member access name
This commit is contained in:
parent
b46b827c30
commit
e2cf5f6ed9
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
10
test/libsolidity/smtCheckerTests/special/difficulty.sol
Normal file
10
test/libsolidity/smtCheckerTests/special/difficulty.sol
Normal 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
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user