diff options
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/GlobalContext.cpp | 2 | ||||
-rw-r--r-- | libsolidity/analysis/SyntaxChecker.cpp | 2 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 2 | ||||
-rw-r--r-- | libsolidity/ast/AST.cpp | 2 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 2 | ||||
-rw-r--r-- | libsolidity/codegen/ContractCompiler.cpp | 4 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 19 | ||||
-rw-r--r-- | libsolidity/formal/Why3Translator.cpp | 113 | ||||
-rw-r--r-- | libsolidity/formal/Why3Translator.h | 6 | ||||
-rw-r--r-- | libsolidity/grammar.txt | 4 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmParser.cpp | 14 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 2 | ||||
-rw-r--r-- | libsolidity/interface/GasEstimator.cpp | 2 |
13 files changed, 139 insertions, 35 deletions
diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index a7ffcfad..d075949e 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -48,6 +48,8 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{make_shared< make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Location::MulMod)), make_shared<MagicVariableDeclaration>("sha3", make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Location::SHA3, true)), + make_shared<MagicVariableDeclaration>("keccak256", + make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Location::SHA3, true)), make_shared<MagicVariableDeclaration>("log0", make_shared<FunctionType>(strings{"bytes32"}, strings{}, FunctionType::Location::Log0)), make_shared<MagicVariableDeclaration>("log1", diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index a95b4879..dc8c1806 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -67,7 +67,7 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) { solAssert(!_pragma.tokens().empty(), ""); solAssert(_pragma.tokens().size() == _pragma.literals().size(), ""); - if (_pragma.tokens()[0] != Token::Identifier && _pragma.literals()[0] != "solidity") + if (_pragma.tokens()[0] != Token::Identifier || _pragma.literals()[0] != "solidity") syntaxError(_pragma.location(), "Unknown pragma \"" + _pragma.literals()[0] + "\""); else { diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index d9c54f75..ae7c13c8 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1438,7 +1438,7 @@ bool TypeChecker::visit(IndexAccess const& _access) length->literalValue(nullptr) )); else - typeError(index->location(), "Integer constant expected."); + fatalTypeError(index->location(), "Integer constant expected."); } break; } diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 294daa13..cca19a4e 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -151,7 +151,7 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::inter if (signaturesSeen.count(functionSignature) == 0) { signaturesSeen.insert(functionSignature); - FixedHash<4> hash(dev::sha3(functionSignature)); + FixedHash<4> hash(dev::keccak256(functionSignature)); m_interfaceFunctionList->push_back(make_pair(hash, fun)); } } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 4b5f12ce..6d1af534 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2033,7 +2033,7 @@ string FunctionType::externalSignature() const u256 FunctionType::externalIdentifier() const { - return FixedHash<4>::Arith(FixedHash<4>(dev::sha3(externalSignature()))); + return FixedHash<4>::Arith(FixedHash<4>(dev::keccak256(externalSignature()))); } TypePointers FunctionType::parseElementaryTypeVector(strings const& _types) diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 33571bc0..18b42fce 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -263,7 +263,9 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac CompilerContext::LocationSetter locationSetter(m_context, functionType->declaration()); m_context << callDataUnpackerEntryPoints.at(it.first); - if (!functionType->isPayable()) + // We have to allow this for libraries, because value of the previous + // call is still visible in the delegatecall. + if (!functionType->isPayable() && !_contract.isLibrary()) { // Throw if function is not payable but call contained ether. m_context << Instruction::CALLVALUE; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 96ca4296..3d05edd3 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -670,7 +670,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) } if (!event.isAnonymous()) { - m_context << u256(h256::Arith(dev::sha3(function.externalSignature()))); + m_context << u256(h256::Arith(dev::keccak256(function.externalSignature()))); ++numIndexed; } solAssert(numIndexed <= 4, "Too many indexed arguments."); @@ -1476,6 +1476,18 @@ void ExpressionCompiler::appendExternalFunctionCall( utils().storeFreeMemoryPointer(); } + // Touch the end of the output area so that we do not pay for memory resize during the call + // (which we would have to subtract from the gas left) + // We could also just use MLOAD; POP right before the gas calculation, but the optimizer + // would remove that, so we use MSTORE here. + if (!_functionType.gasSet() && retSize > 0) + { + m_context << u256(0); + utils().fetchFreeMemoryPointer(); + // This touches too much, but that way we save some rounding arithmetics + m_context << u256(retSize) << Instruction::ADD << Instruction::MSTORE; + } + // Copy function identifier to memory. utils().fetchFreeMemoryPointer(); if (!_functionType.isBareCall() || manualFunctionId) @@ -1551,10 +1563,7 @@ void ExpressionCompiler::appendExternalFunctionCall( gasNeededByCaller += eth::GasCosts::callValueTransferGas; if (!isCallCode && !isDelegateCall && !existenceChecked) gasNeededByCaller += eth::GasCosts::callNewAccountGas; // we never know - m_context << - gasNeededByCaller << - Instruction::GAS << - Instruction::SUB; + m_context << gasNeededByCaller << Instruction::GAS << Instruction::SUB; } if (isDelegateCall) m_context << Instruction::DELEGATECALL; diff --git a/libsolidity/formal/Why3Translator.cpp b/libsolidity/formal/Why3Translator.cpp index b441b150..813fa3ab 100644 --- a/libsolidity/formal/Why3Translator.cpp +++ b/libsolidity/formal/Why3Translator.cpp @@ -36,6 +36,10 @@ bool Why3Translator::process(SourceUnit const& _source) appendPreface(); _source.accept(*this); } + catch (NoFormalType&) + { + solAssert(false, "There is a call to toFormalType() that does not catch NoFormalType exceptions."); + } catch (FatalError& /*_e*/) { solAssert(m_errorOccured, ""); @@ -77,14 +81,30 @@ string Why3Translator::toFormalType(Type const& _type) const return "uint256"; } else if (auto type = dynamic_cast<ArrayType const*>(&_type)) + { if (!type->isByteArray() && type->isDynamicallySized() && type->dataStoredIn(DataLocation::Memory)) { + // Not catching NoFormalType exception. Let the caller deal with it. string base = toFormalType(*type->baseType()); - if (!base.empty()) - return "array " + base; + return "array " + base; } + } + else if (auto mappingType = dynamic_cast<MappingType const*>(&_type)) + { + solAssert(mappingType->keyType(), "A mappingType misses a keyType."); + if (dynamic_cast<IntegerType const*>(&*mappingType->keyType())) + { + //@TODO Use the information from the key type and specify the length of the array as an invariant. + // Also the constructor need to specify the length of the array. + solAssert(mappingType->valueType(), "A mappingType misses a valueType."); + // Not catching NoFormalType exception. Let the caller deal with it. + string valueTypeFormal = toFormalType(*mappingType->valueType()); + return "array " + valueTypeFormal; + } + } - return ""; + BOOST_THROW_EXCEPTION(NoFormalType() + << errinfo_noFormalTypeFrom(_type.toString(true))); } void Why3Translator::addLine(string const& _line) @@ -142,9 +162,17 @@ bool Why3Translator::visit(ContractDefinition const& _contract) m_currentContract.stateVariables = _contract.stateVariables(); for (VariableDeclaration const* variable: m_currentContract.stateVariables) { - string varType = toFormalType(*variable->annotation().type); - if (varType.empty()) - fatalError(*variable, "Type not supported for state variable."); + string varType; + try + { + varType = toFormalType(*variable->annotation().type); + } + catch (NoFormalType &err) + { + string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err); + string typeName = typeNamePtr ? " \"" + *typeNamePtr + "\"" : ""; + fatalError(*variable, "Type" + typeName + " not supported for state variable."); + } addLine("mutable _" + variable->name() + ": " + varType); } unindent(); @@ -218,9 +246,16 @@ bool Why3Translator::visit(FunctionDefinition const& _function) add(" (this: account)"); for (auto const& param: _function.parameters()) { - string paramType = toFormalType(*param->annotation().type); - if (paramType.empty()) - error(*param, "Parameter type not supported."); + string paramType; + try + { + paramType = toFormalType(*param->annotation().type); + } + catch (NoFormalType &err) + { + string const* typeName = boost::get_error_info<errinfo_noFormalTypeFrom>(err); + error(*param, "Parameter type \"" + (typeName ? *typeName : "") + "\" not supported."); + } if (param->name().empty()) error(*param, "Anonymous function parameters not supported."); add(" (arg_" + param->name() + ": " + paramType + ")"); @@ -232,9 +267,16 @@ bool Why3Translator::visit(FunctionDefinition const& _function) string retString = "("; for (auto const& retParam: _function.returnParameters()) { - string paramType = toFormalType(*retParam->annotation().type); - if (paramType.empty()) - error(*retParam, "Parameter type not supported."); + string paramType; + try + { + paramType = toFormalType(*retParam->annotation().type); + } + catch (NoFormalType &err) + { + string const* typeName = boost::get_error_info<errinfo_noFormalTypeFrom>(err); + error(*retParam, "Parameter type " + (typeName ? *typeName : "") + " not supported."); + } if (retString.size() != 1) retString += ", "; retString += paramType; @@ -264,14 +306,32 @@ bool Why3Translator::visit(FunctionDefinition const& _function) { if (variable->name().empty()) error(*variable, "Unnamed return variables not yet supported."); - string varType = toFormalType(*variable->annotation().type); + string varType; + try + { + varType = toFormalType(*variable->annotation().type); + } + catch (NoFormalType &err) + { + string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err); + error(*variable, "Type " + (typeNamePtr ? *typeNamePtr : "") + "in return parameter not yet supported."); + } addLine("let _" + variable->name() + ": ref " + varType + " = ref (of_int 0) in"); } for (VariableDeclaration const* variable: _function.localVariables()) { if (variable->name().empty()) error(*variable, "Unnamed variables not yet supported."); - string varType = toFormalType(*variable->annotation().type); + string varType; + try + { + varType = toFormalType(*variable->annotation().type); + } + catch (NoFormalType &err) + { + string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err); + error(*variable, "Type " + (typeNamePtr ? *typeNamePtr : "") + "in variable declaration not yet supported."); + } addLine("let _" + variable->name() + ": ref " + varType + " = ref (of_int 0) in"); } addLine("try"); @@ -434,8 +494,15 @@ bool Why3Translator::visit(TupleExpression const& _node) bool Why3Translator::visit(UnaryOperation const& _unaryOperation) { - if (toFormalType(*_unaryOperation.annotation().type).empty()) - error(_unaryOperation, "Type not supported in unary operation."); + try + { + toFormalType(*_unaryOperation.annotation().type); + } + catch (NoFormalType &err) + { + string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err); + error(_unaryOperation, "Type \"" + (typeNamePtr ? *typeNamePtr : "") + "\" supported in unary operation."); + } switch (_unaryOperation.getOperator()) { @@ -690,6 +757,20 @@ bool Why3Translator::visit(Literal const& _literal) return false; } +bool Why3Translator::visit(PragmaDirective const& _pragma) +{ + if (_pragma.tokens().empty()) + error(_pragma, "Not supported"); + else if (_pragma.literals().empty()) + error(_pragma, "Not supported"); + else if (_pragma.literals()[0] != "solidity") + error(_pragma, "Not supported"); + else if (_pragma.tokens()[0] != Token::Identifier) + error(_pragma, "A literal 'solidity' is not an identifier. Strange"); + + return false; +} + bool Why3Translator::isStateVariable(VariableDeclaration const* _var) const { return contains(m_currentContract.stateVariables, _var); diff --git a/libsolidity/formal/Why3Translator.h b/libsolidity/formal/Why3Translator.h index 1b80ed61..4fdac385 100644 --- a/libsolidity/formal/Why3Translator.h +++ b/libsolidity/formal/Why3Translator.h @@ -60,9 +60,10 @@ private: /// Appends imports and constants use throughout the formal code. void appendPreface(); - /// @returns a string representation of the corresponding formal type or the empty string - /// if the type is not supported. + /// @returns a string representation of the corresponding formal type or throws NoFormalType exception. std::string toFormalType(Type const& _type) const; + using errinfo_noFormalTypeFrom = boost::error_info<struct tag_noFormalTypeFrom, std::string /* name of the type that cannot be translated */ >; + struct NoFormalType: virtual Exception {}; void indent() { newLine(); m_lines.back().indentation++; } void unindent(); @@ -93,6 +94,7 @@ private: virtual bool visit(IndexAccess const& _node) override; virtual bool visit(Identifier const& _node) override; virtual bool visit(Literal const& _node) override; + virtual bool visit(PragmaDirective const& _node) override; virtual bool visitNode(ASTNode const& _node) override { diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt index 755cf281..d84ee10c 100644 --- a/libsolidity/grammar.txt +++ b/libsolidity/grammar.txt @@ -77,7 +77,7 @@ Expression = | Expression? (',' Expression) | PrimaryExpression -PrimaryExpression = Identifier | BooleanLiteral | NumberLiteral | StringLiteral +PrimaryExpression = Identifier | BooleanLiteral | NumberLiteral | HexLiteral | StringLiteral FunctionCall = ( PrimaryExpression | NewExpression | TypeName ) ( ( '.' Identifier ) | ( '[' Expression ']' ) )* '(' Expression? ( ',' Expression )* ')' NewExpression = 'new' Identifier @@ -88,8 +88,8 @@ BooleanLiteral = 'true' | 'false' NumberLiteral = '0x'? [0-9]+ (' ' NumberUnit)? NumberUnit = 'wei' | 'szabo' | 'finney' | 'ether' | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years' +HexLiteral = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'') StringLiteral = '"' ([^"\r\n\\] | '\\' .)* '"' - Identifier = [a-zA-Z_] [a-zA-Z_0-9]* ElementaryTypeName = 'address' | 'bool' | 'string' | 'var' diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp index 5c7163ee..8d2c2ed4 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libsolidity/inlineasm/AsmParser.cpp @@ -95,7 +95,9 @@ assembly::Statement Parser::parseStatement() fatalParserError("Label name / variable name must precede \":\"."); assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement); m_scanner->next(); - if (m_scanner->currentToken() == Token::Assign) + // identifier:=: should be parsed as identifier: =: (i.e. a label), + // while identifier:= (being followed by a non-colon) as identifier := (assignment). + if (m_scanner->currentToken() == Token::Assign && m_scanner->peekNextToken() != Token::Colon) { // functional assignment FunctionalAssignment funAss = createWithLocation<FunctionalAssignment>(identifier.location); @@ -133,6 +135,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) // Allowed instructions, lowercase names. static map<string, dev::solidity::Instruction> s_instructions; if (s_instructions.empty()) + { for (auto const& instruction: solidity::c_instructions) { if ( @@ -141,24 +144,29 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) ) continue; string name = instruction.first; - if (instruction.second == solidity::Instruction::SUICIDE) - name = "selfdestruct"; transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); }); s_instructions[name] = instruction.second; } + // add alias for selfdestruct + s_instructions["selfdestruct"] = solidity::Instruction::SUICIDE; + } + Statement ret; switch (m_scanner->currentToken()) { case Token::Identifier: case Token::Return: case Token::Byte: + case Token::Address: { string literal; if (m_scanner->currentToken() == Token::Return) literal = "return"; else if (m_scanner->currentToken() == Token::Byte) literal = "byte"; + else if (m_scanner->currentToken() == Token::Address) + literal = "address"; else literal = m_scanner->currentLiteral(); // first search the set of instructions. diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index ec6b5d2e..476721db 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -302,7 +302,7 @@ dev::h256 CompilerStack::contractCodeHash(string const& _contractName) const if (obj.bytecode.empty() || !obj.linkReferences.empty()) return dev::h256(); else - return dev::sha3(obj.bytecode); + return dev::keccak256(obj.bytecode); } Json::Value CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const diff --git a/libsolidity/interface/GasEstimator.cpp b/libsolidity/interface/GasEstimator.cpp index 99ed75bc..1c804b78 100644 --- a/libsolidity/interface/GasEstimator.cpp +++ b/libsolidity/interface/GasEstimator.cpp @@ -136,7 +136,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation( ExpressionClasses& classes = state->expressionClasses(); using Id = ExpressionClasses::Id; using Ids = vector<Id>; - Id hashValue = classes.find(u256(FixedHash<4>::Arith(FixedHash<4>(dev::sha3(_signature))))); + Id hashValue = classes.find(u256(FixedHash<4>::Arith(FixedHash<4>(dev::keccak256(_signature))))); Id calldata = classes.find(Instruction::CALLDATALOAD, Ids{classes.find(u256(0))}); classes.forceEqual(hashValue, Instruction::DIV, Ids{ calldata, |