aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/analysis/GlobalContext.cpp2
-rw-r--r--libsolidity/analysis/SyntaxChecker.cpp2
-rw-r--r--libsolidity/analysis/TypeChecker.cpp2
-rw-r--r--libsolidity/ast/AST.cpp2
-rw-r--r--libsolidity/ast/Types.cpp2
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp4
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp19
-rw-r--r--libsolidity/formal/Why3Translator.cpp113
-rw-r--r--libsolidity/formal/Why3Translator.h6
-rw-r--r--libsolidity/grammar.txt4
-rw-r--r--libsolidity/inlineasm/AsmParser.cpp14
-rw-r--r--libsolidity/interface/CompilerStack.cpp2
-rw-r--r--libsolidity/interface/GasEstimator.cpp2
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,