From 23c414200570b8751bde3fbcb3a3f7105e9ad8f8 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 18 May 2018 18:03:41 +0200 Subject: Bare functions take single bytes argument. --- libsolidity/analysis/GlobalContext.cpp | 8 ++-- libsolidity/analysis/TypeChecker.cpp | 29 ------------ libsolidity/ast/Types.cpp | 25 +++++++++-- libsolidity/ast/Types.h | 5 ++- libsolidity/codegen/ExpressionCompiler.cpp | 71 +++++++----------------------- 5 files changed, 44 insertions(+), 94 deletions(-) (limited to 'libsolidity') diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index 756bb540..7b4bc3aa 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -42,7 +42,7 @@ m_magicVariables(vector>{ make_shared("blockhash", make_shared(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)), make_shared("ecrecover", make_shared(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)), make_shared("gasleft", make_shared(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, false, StateMutability::View)), - make_shared("keccak256", make_shared(strings(), strings{"bytes32"}, FunctionType::Kind::SHA3, true, StateMutability::Pure)), + make_shared("keccak256", make_shared(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA3, false, StateMutability::Pure)), make_shared("log0", make_shared(strings{"bytes32"}, strings{}, FunctionType::Kind::Log0)), make_shared("log1", make_shared(strings{"bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log1)), make_shared("log2", make_shared(strings{"bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log2)), @@ -55,10 +55,10 @@ m_magicVariables(vector>{ make_shared("require", make_shared(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)), make_shared("revert", make_shared(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), make_shared("revert", make_shared(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), - make_shared("ripemd160", make_shared(strings(), strings{"bytes20"}, FunctionType::Kind::RIPEMD160, true, StateMutability::Pure)), + make_shared("ripemd160", make_shared(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)), make_shared("selfdestruct", make_shared(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)), - make_shared("sha256", make_shared(strings(), strings{"bytes32"}, FunctionType::Kind::SHA256, true, StateMutability::Pure)), - make_shared("sha3", make_shared(strings(), strings{"bytes32"}, FunctionType::Kind::SHA3, true, StateMutability::Pure)), + make_shared("sha256", make_shared(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)), + make_shared("sha3", make_shared(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA3, false, StateMutability::Pure)), make_shared("suicide", make_shared(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)), make_shared("tx", make_shared(MagicType::Kind::Transaction)) }) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index b46d4849..ab6b46f4 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1750,35 +1750,6 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) } } - if (functionType->takesSinglePackedBytesParameter()) - { - if ( - (arguments.size() > 1) || - (arguments.size() == 1 && !type(*arguments.front())->isImplicitlyConvertibleTo(ArrayType(DataLocation::Memory))) - ) - { - string msg = - "This function only accepts a single \"bytes\" argument. Please use " - "\"abi.encodePacked(...)\" or a similar function to encode the data."; - if (v050) - m_errorReporter.typeError(_functionCall.location(), msg); - else - m_errorReporter.warning(_functionCall.location(), msg); - } - - if (arguments.size() == 1 && !type(*arguments.front())->isImplicitlyConvertibleTo(ArrayType(DataLocation::Memory))) - { - string msg = - "The provided argument of type " + - type(*arguments.front())->toString() + - " is not implicitly convertible to expected type bytes memory."; - if (v050) - m_errorReporter.typeError(_functionCall.location(), msg); - else - m_errorReporter.warning(_functionCall.location(), msg); - } - } - if (functionType->takesArbitraryParameters() && arguments.size() < parameterTypes.size()) { solAssert(_functionCall.annotation().kind == FunctionCallKind::FunctionCall, ""); diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 68c53af1..fd9ac1e2 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -599,9 +599,9 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons if (isAddress()) return { {"balance", make_shared(256)}, - {"call", make_shared(strings(), strings{"bool"}, FunctionType::Kind::BareCall, true, StateMutability::Payable)}, - {"callcode", make_shared(strings(), strings{"bool"}, FunctionType::Kind::BareCallCode, true, StateMutability::Payable)}, - {"delegatecall", make_shared(strings(), strings{"bool"}, FunctionType::Kind::BareDelegateCall, true)}, + {"call", make_shared(strings{"bytes memory"}, strings{"bool"}, FunctionType::Kind::BareCall, true, StateMutability::Payable)}, + {"callcode", make_shared(strings{"bytes memory"}, strings{"bool"}, FunctionType::Kind::BareCallCode, true, StateMutability::Payable)}, + {"delegatecall", make_shared(strings{"bytes memory"}, strings{"bool"}, FunctionType::Kind::BareDelegateCall, true)}, {"send", make_shared(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)}, {"transfer", make_shared(strings{"uint"}, strings(), FunctionType::Kind::Transfer)} }; @@ -3001,6 +3001,25 @@ ASTPointer FunctionType::documentation() const return ASTPointer(); } +bool FunctionType::padArguments() const +{ + // No padding only for hash functions, low-level calls and the packed encoding function. + switch (m_kind) + { + case Kind::BareCall: + case Kind::BareCallCode: + case Kind::BareDelegateCall: + case Kind::SHA256: + case Kind::RIPEMD160: + case Kind::SHA3: + case Kind::ABIEncodePacked: + return false; + default: + return true; + } + return true; +} + string MappingType::richIdentifier() const { return "t_mapping" + identifierList(m_keyType, m_valueType); diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index d3561fb9..4415fb4b 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1058,8 +1058,9 @@ public: ASTPointer documentation() const; /// true iff arguments are to be padded to multiples of 32 bytes for external calls - /// TODO should this be true in general for bareCall*? - bool padArguments() const { return !(m_kind == Kind::SHA3 || m_kind == Kind::SHA256 || m_kind == Kind::RIPEMD160 || m_kind == Kind::ABIEncodePacked); } + /// The only functions that do not pad are hash functions, the low-level call functions + /// and abi.encodePacked. + bool padArguments() const; bool takesArbitraryParameters() const { return m_arbitraryParameters; } /// true iff the function takes a single bytes parameter and it is passed on without padding. bool takesSinglePackedBytesParameter() const diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 6b0cd92e..e579264e 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1837,39 +1837,12 @@ void ExpressionCompiler::appendExternalFunctionCall( // Evaluate arguments. TypePointers argumentTypes; TypePointers parameterTypes = _functionType.parameterTypes(); - // This can be removed (will always be false) with 0.5.0 - bool manualFunctionId = false; - if ( - (funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall) && - !_arguments.empty() - ) - { - solAssert(_arguments.front()->annotation().type->mobileType(), ""); - manualFunctionId = - _arguments.front()->annotation().type->mobileType()->calldataEncodedSize(false) == - CompilerUtils::dataStartOffset; - } - if (manualFunctionId) - { - // If we have a Bare* and the first type has exactly 4 bytes, use it as - // function identifier. - _arguments.front()->accept(*this); - utils().convertType( - *_arguments.front()->annotation().type, - IntegerType(8 * CompilerUtils::dataStartOffset), - true - ); - for (unsigned i = 0; i < gasValueSize; ++i) - m_context << swapInstruction(gasValueSize - i); - gasStackPos++; - valueStackPos++; - } if (_functionType.bound()) { argumentTypes.push_back(_functionType.selfType()); parameterTypes.insert(parameterTypes.begin(), _functionType.selfType()); } - for (size_t i = manualFunctionId ? 1 : 0; i < _arguments.size(); ++i) + for (size_t i = 0; i < _arguments.size(); ++i) { _arguments[i]->accept(*this); argumentTypes.push_back(_arguments[i]->annotation().type); @@ -1905,36 +1878,22 @@ void ExpressionCompiler::appendExternalFunctionCall( // Copy function identifier to memory. utils().fetchFreeMemoryPointer(); - if (!_functionType.isBareCall() || manualFunctionId) + if (!_functionType.isBareCall()) { m_context << dupInstruction(2 + gasValueSize + CompilerUtils::sizeOnStack(argumentTypes)); utils().storeInMemoryDynamic(IntegerType(8 * CompilerUtils::dataStartOffset), false); } - // This is a function that takes a single bytes parameter which is supposed to be passed - // on inline and without padding. - if (_functionType.takesSinglePackedBytesParameter() && v050 && argumentTypes.size() == 1) - { - utils().encodeToMemory( - argumentTypes, - TypePointers{make_shared(DataLocation::Memory)}, - false, - true - ); - } - else - { - // If the function takes arbitrary parameters, copy dynamic length data in place. - // Move arguments to memory, will not update the free memory pointer (but will update the memory - // pointer on the stack). - utils().encodeToMemory( - argumentTypes, - parameterTypes, - _functionType.padArguments(), - _functionType.takesArbitraryParameters(), - isCallCode || isDelegateCall - ); - } + // If the function takes arbitrary parameters or is a bare call, copy dynamic length data in place. + // Move arguments to memory, will not update the free memory pointer (but will update the memory + // pointer on the stack). + utils().encodeToMemory( + argumentTypes, + parameterTypes, + _functionType.padArguments(), + _functionType.takesArbitraryParameters() || _functionType.isBareCall(), + isCallCode || isDelegateCall + ); // Stack now: // @@ -2013,9 +1972,9 @@ void ExpressionCompiler::appendExternalFunctionCall( unsigned remainsSize = 2 + // contract address, input_memory_end - _functionType.valueSet() + - _functionType.gasSet() + - (!_functionType.isBareCall() || manualFunctionId); + (_functionType.valueSet() ? 1 : 0) + + (_functionType.gasSet() ? 1 : 0) + + (!_functionType.isBareCall() ? 1 : 0); if (returnSuccessCondition) m_context << swapInstruction(remainsSize); -- cgit