diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 593e0960c..8174d138a 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -339,7 +339,7 @@ void Literal::checkTypeRequirements() { m_type = Type::forLiteral(*this); if (!m_type) - BOOST_THROW_EXCEPTION(createTypeError("Literal value too large or too small.")); + BOOST_THROW_EXCEPTION(createTypeError("Literal value too large.")); } } diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 940a5e700..92d574fb1 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -135,7 +135,7 @@ unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, b for (ASTPointer const& var: _function.getParameters()) { unsigned const numBytes = var->getType()->getCalldataEncodedSize(); - if (numBytes == 0 || numBytes > 32) + if (numBytes > 32) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(var->getLocation()) << errinfo_comment("Type " + var->getType()->toString() + " not yet supported.")); @@ -156,7 +156,7 @@ void Compiler::appendReturnValuePacker(FunctionDefinition const& _function) { Type const& paramType = *parameters[i]->getType(); unsigned numBytes = paramType.getCalldataEncodedSize(); - if (numBytes == 0 || numBytes > 32) + if (numBytes > 32) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(parameters[i]->getLocation()) << errinfo_comment("Type " + paramType.toString() + " not yet supported.")); diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index 0ee4a53cb..9f474896e 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -33,9 +33,14 @@ namespace solidity void CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _leftAligned, bool _fromCalldata) { + if (_bytes == 0) + { + m_context << u256(0); + return; + } eth::Instruction load = _fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD; - if (asserts(0 < _bytes && _bytes <= 32)) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Memory load of 0 or more than 32 bytes requested.")); + if (asserts(_bytes <= 32)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Memory load of more than 32 bytes requested.")); if (_bytes == 32) m_context << u256(_offset) << load; else @@ -53,8 +58,13 @@ void CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _left void CompilerUtils::storeInMemory(unsigned _offset, unsigned _bytes, bool _leftAligned) { - if (asserts(0 < _bytes && _bytes <= 32)) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Memory store of 0 or more than 32 bytes requested.")); + if (_bytes == 0) + { + m_context << eth::Instruction::POP; + return; + } + if (asserts(_bytes <= 32)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Memory store of more than 32 bytes requested.")); if (_bytes != 32 && !_leftAligned) // shift the value accordingly before storing m_context << (u256(1) << ((32 - _bytes) * 8)) << eth::Instruction::MUL; diff --git a/libsolidity/Token.h b/libsolidity/Token.h index f9ded3114..21b74eceb 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -269,6 +269,7 @@ namespace solidity K(ADDRESS, "address", 0) \ K(BOOL, "bool", 0) \ K(STRING_TYPE, "string", 0) \ + K(STRING0, "string0", 0) \ K(STRING1, "string1", 0) \ K(STRING2, "string2", 0) \ K(STRING3, "string3", 0) \ diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 543c27c2d..00e530c3f 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -53,8 +53,8 @@ shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) return make_shared(0, IntegerType::Modifier::ADDRESS); else if (_typeToken == Token::BOOL) return make_shared(); - else if (Token::STRING1 <= _typeToken && _typeToken <= Token::STRING32) - return make_shared(int(_typeToken) - int(Token::STRING1) + 1); + else if (Token::STRING0 <= _typeToken && _typeToken <= Token::STRING32) + return make_shared(int(_typeToken) - int(Token::STRING0)); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + std::string(Token::toString(_typeToken)) + " to type.")); @@ -199,14 +199,14 @@ const MemberList IntegerType::AddressMemberList = shared_ptr StaticStringType::smallestTypeForLiteral(string const& _literal) { - if (0 < _literal.length() && _literal.length() <= 32) + if (_literal.length() <= 32) return make_shared(_literal.length()); return shared_ptr(); } StaticStringType::StaticStringType(int _bytes): m_bytes(_bytes) { - if (asserts(m_bytes > 0 && m_bytes <= 32)) + if (asserts(m_bytes >= 0 && m_bytes <= 32)) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid byte number for static string type: " + dev::toString(m_bytes))); } diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index 940ccac63..5523ded39 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -510,6 +510,20 @@ BOOST_AUTO_TEST_CASE(strings) BOOST_CHECK(callContractFunction(1, bytes({0x00, 0x02, 0x01})) == expectation); } +BOOST_AUTO_TEST_CASE(empty_string_on_stack) +{ + char const* sourceCode = "contract test {\n" + " function run(string0 empty, uint8 inp) returns(uint16 a, string0 b, string4 c) {\n" + " var x = \"abc\";\n" + " var y = \"\";\n" + " var z = inp;\n" + " a = z; b = y; c = x;" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction(0, bytes({0x02})) == bytes({0x00, 0x02, 'a', 'b', 'c', 0x00})); +} + BOOST_AUTO_TEST_CASE(state_smoke_test) { char const* sourceCode = "contract test {\n" diff --git a/test/solidityNameAndTypeResolution.cpp b/test/solidityNameAndTypeResolution.cpp index 7357471cc..03eaebb3a 100644 --- a/test/solidityNameAndTypeResolution.cpp +++ b/test/solidityNameAndTypeResolution.cpp @@ -226,14 +226,6 @@ BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } -BOOST_AUTO_TEST_CASE(empty_string_literal) -{ - char const* text = "contract test {\n" - " function f() { var x = \"\"; }" - "}\n"; - BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); -} - BOOST_AUTO_TEST_CASE(large_string_literal) { char const* text = "contract test {\n"