Merge pull request #9106 from ethereum/develop

Merge develop into breaking.
This commit is contained in:
chriseth
2020-06-03 13:51:28 +02:00
committed by GitHub
100 changed files with 1027 additions and 563 deletions
+24 -13
View File
@@ -693,14 +693,6 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
m_errorReporter.typeError(3224_error, _identifier.location, "Constant has no value.");
return size_t(-1);
}
else if (!var || !type(*var)->isValueType() || (
dynamic_cast<Literal const*>(var->value().get()) == nullptr &&
type(*var->value())->category() != Type::Category::RationalNumber
))
{
m_errorReporter.typeError(7615_error, _identifier.location, "Only direct number constants and references to such constants are supported by inline assembly.");
return size_t(-1);
}
else if (_context == yul::IdentifierContext::LValue)
{
m_errorReporter.typeError(6252_error, _identifier.location, "Constant variables cannot be assigned to.");
@@ -711,8 +703,27 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables.");
return size_t(-1);
}
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
{
m_errorReporter.typeError(
2249_error,
_identifier.location,
"Constant variables with non-literal values cannot be forward referenced from inline assembly."
);
return size_t(-1);
}
else if (!var || !type(*var)->isValueType() || (
!dynamic_cast<Literal const*>(var->value().get()) &&
type(*var->value())->category() != Type::Category::RationalNumber
))
{
m_errorReporter.typeError(7615_error, _identifier.location, "Only direct number constants and references to such constants are supported by inline assembly.");
return size_t(-1);
}
}
solAssert(!dynamic_cast<FixedPointType const*>(var->type()), "FixedPointType not implemented.");
if (requiresStorage)
{
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
@@ -2983,7 +2994,11 @@ bool TypeChecker::visit(Identifier const& _identifier)
if (!annotation.referencedDeclaration)
{
annotation.overloadedDeclarations = cleanOverloadedDeclarations(_identifier, annotation.candidateDeclarations);
if (!annotation.arguments)
if (annotation.overloadedDeclarations.empty())
m_errorReporter.fatalTypeError(7593_error, _identifier.location(), "No candidates for overload resolution found.");
else if (annotation.overloadedDeclarations.size() == 1)
annotation.referencedDeclaration = *annotation.overloadedDeclarations.begin();
else if (!annotation.arguments)
{
// The identifier should be a public state variable shadowing other functions
vector<Declaration const*> candidates;
@@ -3000,10 +3015,6 @@ bool TypeChecker::visit(Identifier const& _identifier)
else
m_errorReporter.fatalTypeError(7589_error, _identifier.location(), "No unique declaration found after variable lookup.");
}
else if (annotation.overloadedDeclarations.empty())
m_errorReporter.fatalTypeError(7593_error, _identifier.location(), "No candidates for overload resolution found.");
else if (annotation.overloadedDeclarations.size() == 1)
annotation.referencedDeclaration = *annotation.overloadedDeclarations.begin();
else
{
vector<Declaration const*> candidates;
+3 -6
View File
@@ -172,8 +172,7 @@ void StorageOffsets::computeOffsets(TypePointers const& _types)
++slotOffset;
byteOffset = 0;
}
if (slotOffset >= bigint(1) << 256)
BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << util::errinfo_comment("Object too large for storage."));
solAssert(slotOffset < bigint(1) << 256 ,"Object too large for storage.");
offsets[i] = make_pair(u256(slotOffset), byteOffset);
solAssert(type->storageSize() >= 1, "Invalid storage size.");
if (type->storageSize() == 1 && byteOffset + type->storageBytes() <= 32)
@@ -186,8 +185,7 @@ void StorageOffsets::computeOffsets(TypePointers const& _types)
}
if (byteOffset > 0)
++slotOffset;
if (slotOffset >= bigint(1) << 256)
BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << util::errinfo_comment("Object too large for storage."));
solAssert(slotOffset < bigint(1) << 256, "Object too large for storage.");
m_storageSize = u256(slotOffset);
swap(m_offsets, offsets);
}
@@ -1776,8 +1774,7 @@ u256 ArrayType::storageSize() const
}
else
size = bigint(length()) * baseType()->storageSize();
if (size >= bigint(1) << 256)
BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << util::errinfo_comment("Array too large for storage."));
solAssert(size < bigint(1) << 256, "Array too large for storage.");
return max<u256>(1, u256(size));
}
+6 -1
View File
@@ -422,7 +422,12 @@ void CompilerContext::appendInlineAssembly(
ErrorReporter errorReporter(errors);
auto scanner = make_shared<langutil::Scanner>(langutil::CharStream(_assembly, "--CODEGEN--"));
yul::EVMDialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion);
shared_ptr<yul::Block> parserResult = yul::Parser(errorReporter, dialect).parse(scanner, false);
optional<langutil::SourceLocation> locationOverride;
if (!_system)
locationOverride = m_asm->currentSourceLocation();
shared_ptr<yul::Block> parserResult =
yul::Parser(errorReporter, dialect, std::move(locationOverride))
.parse(scanner, false);
#ifdef SOL_OUTPUT_ASM
cout << yul::AsmPrinter(&dialect)(*parserResult) << endl;
#endif
+3 -3
View File
@@ -701,7 +701,7 @@ vector<smtutil::SortPointer> CHC::stateSorts(ContractDefinition const& _contract
smtutil::SortPointer CHC::constructorSort()
{
return make_shared<smtutil::FunctionSort>(
vector<smtutil::SortPointer>{smtutil::SortProvider::intSort} + m_stateSorts,
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + m_stateSorts,
smtutil::SortProvider::boolSort
);
}
@@ -747,7 +747,7 @@ smtutil::SortPointer CHC::sort(FunctionDefinition const& _function)
auto inputSorts = applyMap(_function.parameters(), smtSort);
auto outputSorts = applyMap(_function.returnParameters(), smtSort);
return make_shared<smtutil::FunctionSort>(
vector<smtutil::SortPointer>{smtutil::SortProvider::intSort} + m_stateSorts + inputSorts + m_stateSorts + inputSorts + outputSorts,
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + m_stateSorts + inputSorts + m_stateSorts + inputSorts + outputSorts,
smtutil::SortProvider::boolSort
);
}
@@ -776,7 +776,7 @@ smtutil::SortPointer CHC::summarySort(FunctionDefinition const& _function, Contr
auto inputSorts = applyMap(_function.parameters(), smtSort);
auto outputSorts = applyMap(_function.returnParameters(), smtSort);
return make_shared<smtutil::FunctionSort>(
vector<smtutil::SortPointer>{smtutil::SortProvider::intSort} + sorts + inputSorts + sorts + outputSorts,
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + sorts + inputSorts + sorts + outputSorts,
smtutil::SortProvider::boolSort
);
}
+67 -7
View File
@@ -274,6 +274,20 @@ bool SMTEncoder::visit(InlineAssembly const& _inlineAsm)
return false;
}
bool SMTEncoder::visit(TryCatchClause const& _clause)
{
if (auto params = _clause.parameters())
for (auto const& var: params->parameters())
createVariable(*var);
m_errorReporter.warning(
7645_error,
_clause.location(),
"Assertion checker does not support try/catch clauses."
);
return false;
}
bool SMTEncoder::visit(IfStatement const& _node)
{
_node.condition().accept(*this);
@@ -361,7 +375,12 @@ void SMTEncoder::endVisit(Assignment const& _assignment)
else if (!smt::isSupportedType(_assignment.annotation().type->category()))
{
// Give it a new index anyway to keep the SSA scheme sound.
if (auto varDecl = identifierToVariable(_assignment.leftHandSide()))
Expression const* base = &_assignment.leftHandSide();
if (auto const* indexAccess = dynamic_cast<IndexAccess const*>(base))
base = leftmostBase(*indexAccess);
if (auto varDecl = identifierToVariable(*base))
m_context.newValue(*varDecl);
}
else
@@ -463,9 +482,6 @@ void SMTEncoder::endVisit(UnaryOperation const& _op)
createExpr(_op);
if (_op.annotation().type->category() == Type::Category::FixedPoint)
return;
switch (_op.getOperator())
{
case Token::Not: // !
@@ -477,8 +493,8 @@ void SMTEncoder::endVisit(UnaryOperation const& _op)
case Token::Inc: // ++ (pre- or postfix)
case Token::Dec: // -- (pre- or postfix)
{
solAssert(smt::isInteger(_op.annotation().type->category()), "");
auto cat = _op.annotation().type->category();
solAssert(smt::isInteger(cat) || smt::isFixedPoint(cat), "");
solAssert(_op.subExpression().annotation().willBeWrittenTo, "");
if (auto identifier = dynamic_cast<Identifier const*>(&_op.subExpression()))
{
@@ -574,6 +590,8 @@ void SMTEncoder::endVisit(BinaryOperation const& _op)
arithmeticOperation(_op);
else if (TokenTraits::isCompareOp(_op.getOperator()))
compareOperation(_op);
else if (TokenTraits::isBitOp(_op.getOperator()))
bitwiseOperation(_op);
else
m_errorReporter.warning(
3876_error,
@@ -1146,6 +1164,12 @@ void SMTEncoder::arrayPushPopAssign(Expression const& _expr, smtutil::Expression
}
else if (auto const* indexAccess = dynamic_cast<IndexAccess const*>(&_expr))
arrayIndexAssignment(*indexAccess, _array);
else if (dynamic_cast<MemberAccess const*>(&_expr))
m_errorReporter.warning(
9599_error,
_expr.location(),
"Assertion checker does not yet implement this expression."
);
else
solAssert(false, "");
}
@@ -1346,6 +1370,43 @@ void SMTEncoder::booleanOperation(BinaryOperation const& _op)
);
}
void SMTEncoder::bitwiseOperation(BinaryOperation const& _op)
{
solAssert(TokenTraits::isBitOp(_op.getOperator()), "");
auto commonType = _op.annotation().commonType;
solAssert(commonType, "");
unsigned bvSize = 256;
bool isSigned = false;
if (auto const* intType = dynamic_cast<IntegerType const*>(commonType))
{
bvSize = intType->numBits();
isSigned = intType->isSigned();
}
else if (auto const* fixedType = dynamic_cast<FixedPointType const*>(commonType))
{
bvSize = fixedType->numBits();
isSigned = fixedType->isSigned();
}
auto bvLeft = smtutil::Expression::int2bv(expr(_op.leftExpression()), bvSize);
auto bvRight = smtutil::Expression::int2bv(expr(_op.rightExpression()), bvSize);
optional<smtutil::Expression> result;
if (_op.getOperator() == Token::BitAnd)
result = bvLeft & bvRight;
// TODO implement the other operators
else
m_errorReporter.warning(
1093_error,
_op.location(),
"Assertion checker does not yet implement this bitwise operator."
);
if (result)
defineExpr(_op, smtutil::Expression::bv2int(*result, isSigned));
}
smtutil::Expression SMTEncoder::division(smtutil::Expression _left, smtutil::Expression _right, IntegerType const& _type)
{
// Signed division in SMTLIB2 rounds differently for negative division.
@@ -1755,7 +1816,6 @@ Expression const* SMTEncoder::leftmostBase(IndexAccess const& _indexAccess)
set<VariableDeclaration const*> SMTEncoder::touchedVariables(ASTNode const& _node)
{
solAssert(!m_callStack.empty(), "");
vector<CallableDeclaration const*> callStack;
for (auto const& call: m_callStack)
callStack.push_back(call.first);
+2
View File
@@ -91,6 +91,7 @@ protected:
bool visit(InlineAssembly const& _node) override;
void endVisit(Break const&) override {}
void endVisit(Continue const&) override {}
bool visit(TryCatchClause const& _node) override;
/// Do not visit subtree if node is a RationalNumber.
/// Symbolic _expr is the rational literal.
@@ -108,6 +109,7 @@ protected:
);
void compareOperation(BinaryOperation const& _op);
void booleanOperation(BinaryOperation const& _op);
void bitwiseOperation(BinaryOperation const& _op);
void initContract(ContractDefinition const& _contract);
void initFunction(FunctionDefinition const& _function);
+1 -1
View File
@@ -63,7 +63,7 @@ private:
/// Symbolic balances.
SymbolicArrayVariable m_balances{
std::make_shared<smtutil::ArraySort>(smtutil::SortProvider::intSort, smtutil::SortProvider::intSort),
std::make_shared<smtutil::ArraySort>(smtutil::SortProvider::uintSort, smtutil::SortProvider::uintSort),
"balances",
m_context
};
+20 -8
View File
@@ -34,7 +34,11 @@ SortPointer smtSort(frontend::Type const& _type)
switch (smtKind(_type.category()))
{
case Kind::Int:
return SortProvider::intSort;
if (auto const* intType = dynamic_cast<IntegerType const*>(&_type))
return SortProvider::intSort(intType->isSigned());
if (auto const* fixedType = dynamic_cast<FixedPointType const*>(&_type))
return SortProvider::intSort(fixedType->isSigned());
return SortProvider::uintSort;
case Kind::Bool:
return SortProvider::boolSort;
case Kind::Function:
@@ -50,7 +54,7 @@ SortPointer smtSort(frontend::Type const& _type)
returnSort = SortProvider::boolSort;
else if (returnTypes.size() > 1)
// Abstract sort.
returnSort = SortProvider::intSort;
returnSort = SortProvider::uintSort;
else
returnSort = smtSort(*returnTypes.front());
return make_shared<FunctionSort>(parameterSorts, returnSort);
@@ -68,7 +72,7 @@ SortPointer smtSort(frontend::Type const& _type)
{
auto stringLitType = dynamic_cast<frontend::StringLiteralType const*>(&_type);
solAssert(stringLitType, "");
array = make_shared<ArraySort>(SortProvider::intSort, SortProvider::intSort);
array = make_shared<ArraySort>(SortProvider::uintSort, SortProvider::uintSort);
}
else
{
@@ -81,7 +85,7 @@ SortPointer smtSort(frontend::Type const& _type)
solAssert(false, "");
solAssert(arrayType, "");
array = make_shared<ArraySort>(SortProvider::intSort, smtSortAbstractFunction(*arrayType->baseType()));
array = make_shared<ArraySort>(SortProvider::uintSort, smtSortAbstractFunction(*arrayType->baseType()));
}
string tupleName;
@@ -98,7 +102,7 @@ SortPointer smtSort(frontend::Type const& _type)
return make_shared<TupleSort>(
tupleName,
vector<string>{tupleName + "_accessor_array", tupleName + "_accessor_length"},
vector<SortPointer>{array, SortProvider::intSort}
vector<SortPointer>{array, SortProvider::uintSort}
);
}
case Kind::Tuple:
@@ -118,7 +122,7 @@ SortPointer smtSort(frontend::Type const& _type)
}
default:
// Abstract case.
return SortProvider::intSort;
return SortProvider::uintSort;
}
}
@@ -133,7 +137,7 @@ vector<SortPointer> smtSort(vector<frontend::TypePointer> const& _types)
SortPointer smtSortAbstractFunction(frontend::Type const& _type)
{
if (isFunction(_type.category()))
return SortProvider::intSort;
return SortProvider::uintSort;
return smtSort(_type);
}
@@ -144,7 +148,7 @@ vector<SortPointer> smtSortAbstractFunction(vector<frontend::TypePointer> const&
if (type)
sorts.push_back(smtSortAbstractFunction(*type));
else
sorts.push_back(SortProvider::intSort);
sorts.push_back(SortProvider::uintSort);
return sorts;
}
@@ -220,6 +224,8 @@ pair<bool, shared_ptr<SymbolicVariable>> newSymbolicVariable(
}
else if (isInteger(_type.category()))
var = make_shared<SymbolicIntVariable>(type, type, _uniqueName, _context);
else if (isFixedPoint(_type.category()))
var = make_shared<SymbolicIntVariable>(type, type, _uniqueName, _context);
else if (isFixedBytes(_type.category()))
{
auto fixedBytesType = dynamic_cast<frontend::FixedBytesType const*>(type);
@@ -268,6 +274,11 @@ bool isInteger(frontend::Type::Category _category)
return _category == frontend::Type::Category::Integer;
}
bool isFixedPoint(frontend::Type::Category _category)
{
return _category == frontend::Type::Category::FixedPoint;
}
bool isRational(frontend::Type::Category _category)
{
return _category == frontend::Type::Category::RationalNumber;
@@ -296,6 +307,7 @@ bool isEnum(frontend::Type::Category _category)
bool isNumber(frontend::Type::Category _category)
{
return isInteger(_category) ||
isFixedPoint(_category) ||
isRational(_category) ||
isFixedBytes(_category) ||
isAddress(_category) ||
+1
View File
@@ -43,6 +43,7 @@ bool isSupportedTypeDeclaration(frontend::Type::Category _category);
bool isSupportedTypeDeclaration(frontend::Type const& _type);
bool isInteger(frontend::Type::Category _category);
bool isFixedPoint(frontend::Type::Category _category);
bool isRational(frontend::Type::Category _category);
bool isFixedBytes(frontend::Type::Category _category);
bool isAddress(frontend::Type::Category _category);
+1 -1
View File
@@ -286,7 +286,7 @@ SymbolicArrayVariable::SymbolicArrayVariable(
std::make_shared<TupleSort>(
"array_length_pair",
std::vector<std::string>{"array", "length"},
std::vector<SortPointer>{m_sort, SortProvider::intSort}
std::vector<SortPointer>{m_sort, SortProvider::uintSort}
),
m_uniqueName + "_array_length_pair",
m_context
+3 -3
View File
@@ -33,7 +33,8 @@ set<VariableDeclaration const*> VariableUsage::touchedVariables(ASTNode const& _
m_touchedVariables.clear();
m_callStack.clear();
m_callStack += _outerCallstack;
m_lastCall = m_callStack.back();
if (!m_callStack.empty())
m_lastCall = m_callStack.back();
_node.accept(*this);
return m_touchedVariables;
}
@@ -103,8 +104,7 @@ void VariableUsage::checkIdentifier(Identifier const& _identifier)
solAssert(declaration, "");
if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
{
solAssert(m_lastCall, "");
if (!varDecl->isLocalVariable() || varDecl->functionOrModifierDefinition() == m_lastCall)
if (!varDecl->isLocalVariable() || (m_lastCall && varDecl->functionOrModifierDefinition() == m_lastCall))
m_touchedVariables.insert(varDecl);
}
}