Merge pull request #1308 from ethereum/develop

Merge for version 0.4.4
This commit is contained in:
chriseth 2016-10-31 19:21:04 +01:00 committed by GitHub
commit 4633f3def8
13 changed files with 96 additions and 39 deletions

View File

@ -8,7 +8,7 @@ include(EthPolicy)
eth_policy() eth_policy()
# project name and version should be set after cmake_policy CMP0048 # project name and version should be set after cmake_policy CMP0048
set(PROJECT_VERSION "0.4.3") set(PROJECT_VERSION "0.4.4")
project(solidity VERSION ${PROJECT_VERSION}) project(solidity VERSION ${PROJECT_VERSION})
# Let's find our dependencies # Let's find our dependencies

View File

@ -1,3 +1,9 @@
### 0.4.4 (2016-10-31)
Bugfixes:
* Type checker: forbid signed exponential that led to an incorrect use of EXP opcode.
* Code generator: properly clean higher order bytes before storing in storage.
### 0.4.3 (2016-10-25) ### 0.4.3 (2016-10-25)
Features: Features:

View File

@ -180,12 +180,12 @@ elseif (DEFINED MSVC)
# Always use Release variant of C++ runtime. # Always use Release variant of C++ runtime.
# We don't want to provide Debug variants of all dependencies. Some default # We don't want to provide Debug variants of all dependencies. Some default
# flags set by CMake must be tweaked. # flags set by CMake must be tweaked.
string(REPLACE "/MDd" "/MD" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) string(REPLACE "/MDd" "/MD" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "/D_DEBUG" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) string(REPLACE "/D_DEBUG" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "/MDd" "/MD" CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG}) string(REPLACE "/MDd" "/MD" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
string(REPLACE "/D_DEBUG" "" CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG}) string(REPLACE "/D_DEBUG" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
string(REPLACE "/RTC1" "" CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG}) string(REPLACE "/RTC1" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
set_property(GLOBAL PROPERTY DEBUG_CONFIGURATIONS OFF) set_property(GLOBAL PROPERTY DEBUG_CONFIGURATIONS OFF)
# disable empty object file warning # disable empty object file warning

View File

@ -119,7 +119,7 @@ function(eth_use TARGET REQUIRED)
endif() endif()
foreach(MODULE ${ARGN}) foreach(MODULE ${ARGN})
string(REPLACE "::" ";" MODULE_PARTS ${MODULE}) string(REPLACE "::" ";" MODULE_PARTS "${MODULE}")
list(GET MODULE_PARTS 0 MODULE_MAIN) list(GET MODULE_PARTS 0 MODULE_MAIN)
list(LENGTH MODULE_PARTS MODULE_LENGTH) list(LENGTH MODULE_PARTS MODULE_LENGTH)
if (MODULE_LENGTH GREATER 1) if (MODULE_LENGTH GREATER 1)

View File

@ -56,9 +56,9 @@ copyright = '2016, Ethereum'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.4.3' version = '0.4.4'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.4.3-develop' release = '0.4.4-develop'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@ -5,7 +5,7 @@ Solidity is a contract-oriented, high-level language whose syntax is similar to
and it is designed to target the Ethereum Virtual Machine. and it is designed to target the Ethereum Virtual Machine.
Solidity is statically typed, supports inheritance, libraries and complex Solidity is statically typed, supports inheritance, libraries and complex
user-defines types among other features. user-defined types among other features.
As you will see, it is possible to create contracts for voting, As you will see, it is possible to create contracts for voting,
crowdfunding, blind auctions, multi-signature wallets and more. crowdfunding, blind auctions, multi-signature wallets and more.

View File

@ -12,7 +12,7 @@ Versioning
Solidity versions follow `semantic versioning <https://semver.org>`_ and in addition to Solidity versions follow `semantic versioning <https://semver.org>`_ and in addition to
releases, **nightly development builds** are also made available. The nightly builds releases, **nightly development builds** are also made available. The nightly builds
are not guaranteed to be working and despite best efforts they might contain undocumented are not guaranteed to be working and despite best efforts they might contain undocumented
and/or broken changes. We recommend to use the latest release. Package installers below and/or broken changes. We recommend using the latest release. Package installers below
will use the latest release. will use the latest release.
Browser-Solidity Browser-Solidity

View File

@ -330,9 +330,32 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
if (nonStandard) if (nonStandard)
return; return;
std::map<std::string, Instruction> const c_arith = { { "+", Instruction::ADD }, { "-", Instruction::SUB }, { "*", Instruction::MUL }, { "/", Instruction::DIV }, { "%", Instruction::MOD }, { "&", Instruction::AND }, { "|", Instruction::OR }, { "^", Instruction::XOR } }; std::map<std::string, Instruction> const c_arith = {
std::map<std::string, pair<Instruction, bool>> const c_binary = { { "<", { Instruction::LT, false } }, { "<=", { Instruction::GT, true } }, { ">", { Instruction::GT, false } }, { ">=", { Instruction::LT, true } }, { "S<", { Instruction::SLT, false } }, { "S<=", { Instruction::SGT, true } }, { "S>", { Instruction::SGT, false } }, { "S>=", { Instruction::SLT, true } }, { "=", { Instruction::EQ, false } }, { "!=", { Instruction::EQ, true } } }; { "+", Instruction::ADD },
std::map<std::string, Instruction> const c_unary = { { "!", Instruction::ISZERO } }; { "-", Instruction::SUB },
{ "*", Instruction::MUL },
{ "/", Instruction::DIV },
{ "%", Instruction::MOD },
{ "&", Instruction::AND },
{ "|", Instruction::OR },
{ "^", Instruction::XOR }
};
std::map<std::string, pair<Instruction, bool>> const c_binary = {
{ "<", { Instruction::LT, false } },
{ "<=", { Instruction::GT, true } },
{ ">", { Instruction::GT, false } },
{ ">=", { Instruction::LT, true } },
{ "S<", { Instruction::SLT, false } },
{ "S<=", { Instruction::SGT, true } },
{ "S>", { Instruction::SGT, false } },
{ "S>=", { Instruction::SLT, true } },
{ "=", { Instruction::EQ, false } },
{ "!=", { Instruction::EQ, true } }
};
std::map<std::string, Instruction> const c_unary = {
{ "!", Instruction::ISZERO },
{ "~", Instruction::NOT }
};
vector<CodeFragment> code; vector<CodeFragment> code;
CompilerState ns = _s; CompilerState ns = _s;
@ -449,13 +472,14 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
m_asm << end.tag(); m_asm << end.tag();
m_asm.donePaths(); m_asm.donePaths();
} }
else if (us == "WHILE") else if (us == "WHILE" || us == "UNTIL")
{ {
requireSize(2); requireSize(2);
requireDeposit(0, 1); requireDeposit(0, 1);
auto begin = m_asm.append(); auto begin = m_asm.append();
m_asm.append(code[0].m_asm); m_asm.append(code[0].m_asm);
if (us == "WHILE")
m_asm.append(Instruction::ISZERO); m_asm.append(Instruction::ISZERO);
auto end = m_asm.appendJumpI(); auto end = m_asm.appendJumpI();
m_asm.append(code[1].m_asm, 0); m_asm.append(code[1].m_asm, 0);
@ -541,17 +565,6 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
// At end now. // At end now.
m_asm.append(end); m_asm.append(end);
} }
else if (us == "~")
{
requireSize(1);
requireDeposit(0, 1);
m_asm.append(code[0].m_asm, 1);
m_asm.append((u256)1);
m_asm.append((u256)0);
m_asm.append(Instruction::SUB);
m_asm.append(Instruction::SUB);
}
else if (us == "SEQ") else if (us == "SEQ")
{ {
unsigned ii = 0; unsigned ii = 0;
@ -567,6 +580,10 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
m_asm.append(i.m_asm); m_asm.append(i.m_asm);
m_asm.popTo(1); m_asm.popTo(1);
} }
else if (us == "PANIC")
{
m_asm.appendJump(m_asm.errorTag());
}
else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos) else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos)
m_asm.append((u256)varAddress(s)); m_asm.append((u256)varAddress(s));
else else

View File

@ -349,11 +349,14 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
return commonType; return commonType;
if (Token::isBooleanOp(_operator)) if (Token::isBooleanOp(_operator))
return TypePointer(); return TypePointer();
// Nothing else can be done with addresses
if (auto intType = dynamic_pointer_cast<IntegerType const>(commonType)) if (auto intType = dynamic_pointer_cast<IntegerType const>(commonType))
{ {
// Nothing else can be done with addresses
if (intType->isAddress()) if (intType->isAddress())
return TypePointer(); return TypePointer();
// Signed EXP is not allowed
if (Token::Exp == _operator && intType->isSigned())
return TypePointer();
} }
else if (auto fixType = dynamic_pointer_cast<FixedPointType const>(commonType)) else if (auto fixType = dynamic_pointer_cast<FixedPointType const>(commonType))
if (Token::Exp == _operator) if (Token::Exp == _operator)

View File

@ -231,10 +231,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
m_context m_context
<< (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(*m_dataType).numBytes())) << (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(*m_dataType).numBytes()))
<< Instruction::SWAP1 << Instruction::DIV; << Instruction::SWAP1 << Instruction::DIV;
else if ( else
m_dataType->category() == Type::Category::Integer &&
dynamic_cast<IntegerType const&>(*m_dataType).isSigned()
)
// remove the higher order bits // remove the higher order bits
m_context m_context
<< (u256(1) << (8 * (32 - m_dataType->storageBytes()))) << (u256(1) << (8 * (32 - m_dataType->storageBytes())))
@ -242,9 +239,6 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
<< Instruction::DUP2 << Instruction::DUP2
<< Instruction::MUL << Instruction::MUL
<< Instruction::DIV; << Instruction::DIV;
else if (m_dataType->category() == Type::Category::FixedPoint)
// implementation should be very similar to the integer case.
solAssert(false, "Not yet implemented - FixedPointType.");
m_context << Instruction::MUL << Instruction::OR; m_context << Instruction::MUL << Instruction::OR;
// stack: value storage_ref updated_value // stack: value storage_ref updated_value
m_context << Instruction::SWAP1 << Instruction::SSTORE; m_context << Instruction::SWAP1 << Instruction::SSTORE;

View File

@ -41,6 +41,7 @@ void help()
<< " -x,--hex Parse, compile and assemble; output byte code in hex." << endl << " -x,--hex Parse, compile and assemble; output byte code in hex." << endl
<< " -a,--assembly Only parse and compile; show assembly." << endl << " -a,--assembly Only parse and compile; show assembly." << endl
<< " -t,--parse-tree Only parse; show parse tree." << endl << " -t,--parse-tree Only parse; show parse tree." << endl
<< " -o,--optimise Turn on/off the optimiser; off by default." << endl
<< " -h,--help Show this help message and exit." << endl << " -h,--help Show this help message and exit." << endl
<< " -V,--version Show the version and exit." << endl; << " -V,--version Show the version and exit." << endl;
exit(0); exit(0);
@ -81,7 +82,7 @@ enum Mode { Binary, Hex, Assembly, ParseTree, Disassemble };
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
setDefaultOrCLocale(); setDefaultOrCLocale();
unsigned optimise = 1; unsigned optimise = 0;
string infile; string infile;
Mode mode = Hex; Mode mode = Hex;
@ -98,8 +99,8 @@ int main(int argc, char** argv)
mode = Assembly; mode = Assembly;
else if (arg == "-t" || arg == "--parse-tree") else if (arg == "-t" || arg == "--parse-tree")
mode = ParseTree; mode = ParseTree;
else if ((arg == "-o" || arg == "--optimise") && argc > i + 1) else if (arg == "-o" || arg == "--optimise")
optimise = atoi(argv[++i]); optimise = 1;
else if (arg == "-d" || arg == "--disassemble") else if (arg == "-d" || arg == "--disassemble")
mode = Disassemble; mode = Disassemble;
else if (arg == "-V" || arg == "--version") else if (arg == "-V" || arg == "--version")

View File

@ -7533,6 +7533,26 @@ BOOST_AUTO_TEST_CASE(inline_assembly_in_modifiers)
BOOST_CHECK(callContractFunction("f()") == encodeArgs(true)); BOOST_CHECK(callContractFunction("f()") == encodeArgs(true));
} }
BOOST_AUTO_TEST_CASE(packed_storage_overflow)
{
char const* sourceCode = R"(
contract C {
uint16 x = 0x1234;
uint16 a = 0xffff;
uint16 b;
function f() returns (uint, uint, uint, uint) {
a++;
uint c = b;
delete b;
a -= 2;
return (x, c, b, a);
}
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0x1234), u256(0), u256(0), u256(0xfffe)));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

View File

@ -2098,6 +2098,22 @@ BOOST_AUTO_TEST_CASE(integer_boolean_operators)
BOOST_CHECK(expectError(sourceCode3) == Error::Type::TypeError); BOOST_CHECK(expectError(sourceCode3) == Error::Type::TypeError);
} }
BOOST_AUTO_TEST_CASE(exp_signed_variable)
{
char const* sourceCode1 = R"(
contract test { function() { uint x = 3; int y = -4; x ** y; } }
)";
BOOST_CHECK(expectError(sourceCode1) == Error::Type::TypeError);
char const* sourceCode2 = R"(
contract test { function() { uint x = 3; int y = -4; y ** x; } }
)";
BOOST_CHECK(expectError(sourceCode2) == Error::Type::TypeError);
char const* sourceCode3 = R"(
contract test { function() { int x = -3; int y = -4; x ** y; } }
)";
BOOST_CHECK(expectError(sourceCode3) == Error::Type::TypeError);
}
BOOST_AUTO_TEST_CASE(reference_compare_operators) BOOST_AUTO_TEST_CASE(reference_compare_operators)
{ {
char const* sourceCode1 = R"( char const* sourceCode1 = R"(