Skip to content

Commit

Permalink
Add new arithmetic operator to avoid overflow issues
Browse files Browse the repository at this point in the history
  • Loading branch information
hydai authored and dm4 committed Jun 13, 2018
1 parent 028e0da commit a4be6e1
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 11 deletions.
8 changes: 8 additions & 0 deletions libevmasm/Instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ const std::map<std::string, Instruction> dev::solidity::c_instructions =
{
{ "STOP", Instruction::STOP },
{ "ADD", Instruction::ADD },
{ "SADD", Instruction::SADD },
{ "SUB", Instruction::SUB },
{ "SSUB", Instruction::SSUB },
{ "MUL", Instruction::MUL },
{ "SMUL", Instruction::SMUL },
{ "DIV", Instruction::DIV },
{ "SDIV", Instruction::SDIV },
{ "MOD", Instruction::MOD },
Expand All @@ -57,6 +60,7 @@ const std::map<std::string, Instruction> dev::solidity::c_instructions =
{ "MULMOD", Instruction::MULMOD },
{ "SIGNEXTEND", Instruction::SIGNEXTEND },
{ "KECCAK256", Instruction::KECCAK256 },
{ "ENI", Instruction::ENI },
{ "ADDRESS", Instruction::ADDRESS },
{ "BALANCE", Instruction::BALANCE },
{ "ORIGIN", Instruction::ORIGIN },
Expand Down Expand Up @@ -175,8 +179,11 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ // Add, Args, Ret, SideEffects, GasPriceTier
{ Instruction::STOP, { "STOP", 0, 0, 0, true, Tier::Zero } },
{ Instruction::ADD, { "ADD", 0, 2, 1, false, Tier::VeryLow } },
{ Instruction::SADD, { "SADD", 0, 2, 1, false, Tier::VeryLow } },
{ Instruction::SUB, { "SUB", 0, 2, 1, false, Tier::VeryLow } },
{ Instruction::SSUB, { "SSUB", 0, 2, 1, false, Tier::VeryLow } },
{ Instruction::MUL, { "MUL", 0, 2, 1, false, Tier::Low } },
{ Instruction::SMUL, { "SMUL", 0, 2, 1, false, Tier::Low } },
{ Instruction::DIV, { "DIV", 0, 2, 1, false, Tier::Low } },
{ Instruction::SDIV, { "SDIV", 0, 2, 1, false, Tier::Low } },
{ Instruction::MOD, { "MOD", 0, 2, 1, false, Tier::Low } },
Expand All @@ -200,6 +207,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::MULMOD, { "MULMOD", 0, 3, 1, false, Tier::Mid } },
{ Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1, false, Tier::Low } },
{ Instruction::KECCAK256, { "KECCAK256", 0, 2, 1, true, Tier::Special } },
{ Instruction::ENI, { "ENI", 0, 2, 1, true, Tier::Special } },
{ Instruction::ADDRESS, { "ADDRESS", 0, 0, 1, false, Tier::Base } },
{ Instruction::BALANCE, { "BALANCE", 0, 1, 1, false, Tier::Balance } },
{ Instruction::ORIGIN, { "ORIGIN", 0, 0, 1, false, Tier::Base } },
Expand Down
11 changes: 8 additions & 3 deletions libevmasm/Instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ DEV_SIMPLE_EXCEPTION(InvalidOpcode);
enum class Instruction: uint8_t
{
STOP = 0x00, ///< halts execution
ADD, ///< addition operation
MUL, ///< multiplication operation
SUB, ///< subtraction operation
ADD, ///< unsigned addition operation
MUL, ///< unsigned multiplication operation
SUB, ///< unsigned subtraction operation
DIV, ///< integer division operation
SDIV, ///< signed integer division operation
MOD, ///< modulo remainder operation
Expand Down Expand Up @@ -187,11 +187,16 @@ enum class Instruction: uint8_t
PUTLOCAL, ///< pop top of stack to local variable -- not part of Instructions.cpp
GETLOCAL, ///< push local variable to top of stack -- not part of Instructions.cpp

SADD = 0xc0, ///< signed addition operation with overflow checking
SSUB, ///< signed subtraction operation with overflow checking
SMUL, ///< signed multiplication operation with overflow checking

CREATE = 0xf0, ///< create a new account with associated code
CALL, ///< message-call into an account
CALLCODE, ///< message-call with another account's code only
RETURN, ///< halt execution returning output data
DELEGATECALL, ///< like CALLCODE but keeps caller's value and sender
ENI,
STATICCALL = 0xfa, ///< like CALL but disallow state modifications
CREATE2 = 0xfb, ///< create new account with associated code at address `sha3(sender + salt + sha3(init code)) % 2**160`

Expand Down
41 changes: 41 additions & 0 deletions libevmasm/RuleList.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,11 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList(
rules += std::vector<SimplificationRule<Pattern>>{
// arithmetics on constants
{{Instruction::ADD, {A, B}}, [=]{ return A.d() + B.d(); }, false},
{{Instruction::SADD, {A, B}}, [=]{ return A.d() + B.d(); }, false},
{{Instruction::MUL, {A, B}}, [=]{ return A.d() * B.d(); }, false},
{{Instruction::SMUL, {A, B}}, [=]{ return A.d() * B.d(); }, false},
{{Instruction::SUB, {A, B}}, [=]{ return A.d() - B.d(); }, false},
{{Instruction::SSUB, {A, B}}, [=]{ return A.d() - B.d(); }, false},
{{Instruction::DIV, {A, B}}, [=]{ return B.d() == 0 ? 0 : divWorkaround(A.d(), B.d()); }, false},
{{Instruction::SDIV, {A, B}}, [=]{ return B.d() == 0 ? 0 : s2u(divWorkaround(u2s(A.d()), u2s(B.d()))); }, false},
{{Instruction::MOD, {A, B}}, [=]{ return B.d() == 0 ? 0 : modWorkaround(A.d(), B.d()); }, false},
Expand Down Expand Up @@ -103,13 +106,22 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList(
// invariants involving known constants
{{Instruction::ADD, {X, 0}}, [=]{ return X; }, false},
{{Instruction::ADD, {0, X}}, [=]{ return X; }, false},
{{Instruction::SADD, {X, 0}}, [=]{ return X; }, false},
{{Instruction::SADD, {0, X}}, [=]{ return X; }, false},
{{Instruction::SUB, {X, 0}}, [=]{ return X; }, false},
{{Instruction::SSUB, {X, 0}}, [=]{ return X; }, false},
{{Instruction::MUL, {X, 0}}, [=]{ return u256(0); }, true},
{{Instruction::MUL, {0, X}}, [=]{ return u256(0); }, true},
{{Instruction::MUL, {X, 1}}, [=]{ return X; }, false},
{{Instruction::MUL, {1, X}}, [=]{ return X; }, false},
{{Instruction::MUL, {X, u256(-1)}}, [=]() -> Pattern { return {Instruction::SUB, {0, X}}; }, false},
{{Instruction::MUL, {u256(-1), X}}, [=]() -> Pattern { return {Instruction::SUB, {0, X}}; }, false},
{{Instruction::SMUL, {X, 0}}, [=]{ return u256(0); }, true},
{{Instruction::SMUL, {0, X}}, [=]{ return u256(0); }, true},
{{Instruction::SMUL, {X, 1}}, [=]{ return X; }, false},
{{Instruction::SMUL, {1, X}}, [=]{ return X; }, false},
{{Instruction::SMUL, {X, u256(-1)}}, [=]() -> Pattern { return {Instruction::SSUB, {0, X}}; }, false},
{{Instruction::SMUL, {u256(-1), X}}, [=]() -> Pattern { return {Instruction::SSUB, {0, X}}; }, false},
{{Instruction::DIV, {X, 0}}, [=]{ return u256(0); }, true},
{{Instruction::DIV, {0, X}}, [=]{ return u256(0); }, true},
{{Instruction::DIV, {X, 1}}, [=]{ return X; }, false},
Expand All @@ -136,6 +148,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList(
{{Instruction::OR, {X, X}}, [=]{ return X; }, true},
{{Instruction::XOR, {X, X}}, [=]{ return u256(0); }, true},
{{Instruction::SUB, {X, X}}, [=]{ return u256(0); }, true},
{{Instruction::SSUB, {X, X}}, [=]{ return u256(0); }, true},
{{Instruction::EQ, {X, X}}, [=]{ return u256(1); }, true},
{{Instruction::LT, {X, X}}, [=]{ return u256(0); }, true},
{{Instruction::SLT, {X, X}}, [=]{ return u256(0); }, true},
Expand Down Expand Up @@ -223,7 +236,9 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList(
// Associative operations
for (auto const& opFun: std::vector<std::pair<Instruction,std::function<u256(u256 const&,u256 const&)>>>{
{Instruction::ADD, std::plus<u256>()},
{Instruction::SADD, std::plus<u256>()},
{Instruction::MUL, std::multiplies<u256>()},
{Instruction::SMUL, std::multiplies<u256>()},
{Instruction::AND, std::bit_and<u256>()},
{Instruction::OR, std::bit_or<u256>()},
{Instruction::XOR, std::bit_xor<u256>()}
Expand Down Expand Up @@ -287,6 +302,32 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList(
{Instruction::SUB, {X, {Instruction::ADD, {A, Y}}}},
[=]() -> Pattern { return {Instruction::ADD, {{Instruction::SUB, {X, Y}}, 0 - A.d()}}; },
false
},
{
// X - A -> X + (-A)
{Instruction::SSUB, {X, A}},
[=]() -> Pattern { return {Instruction::SADD, {X, 0 - A.d()}}; },
false
}, {
// (X + A) - Y -> (X - Y) + A
{Instruction::SSUB, {{Instruction::SADD, {X, A}}, Y}},
[=]() -> Pattern { return {Instruction::SADD, {{Instruction::SSUB, {X, Y}}, A}}; },
false
}, {
// (A + X) - Y -> (X - Y) + A
{Instruction::SSUB, {{Instruction::SADD, {A, X}}, Y}},
[=]() -> Pattern { return {Instruction::SADD, {{Instruction::SSUB, {X, Y}}, A}}; },
false
}, {
// X - (Y + A) -> (X - Y) + (-A)
{Instruction::SSUB, {X, {Instruction::SADD, {Y, A}}}},
[=]() -> Pattern { return {Instruction::SADD, {{Instruction::SSUB, {X, Y}}, 0 - A.d()}}; },
false
}, {
// X - (A + Y) -> (X - Y) + (-A)
{Instruction::SSUB, {X, {Instruction::SADD, {A, Y}}}},
[=]() -> Pattern { return {Instruction::SADD, {{Instruction::SSUB, {X, Y}}, 0 - A.d()}}; },
false
}
};
return rules;
Expand Down
16 changes: 8 additions & 8 deletions libsolidity/codegen/ExpressionCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,19 +281,19 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
if (_tuple.isInlineArray())
{
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*_tuple.annotation().type);

solAssert(!arrayType.isDynamicallySized(), "Cannot create dynamically sized inline array.");
m_context << max(u256(32u), arrayType.memorySize());
utils().allocateMemory();
m_context << Instruction::DUP1;

for (auto const& component: _tuple.components())
{
component->accept(*this);
utils().convertType(*component->annotation().type, *arrayType.baseType(), true);
utils().storeInMemoryDynamic(*arrayType.baseType(), true);
utils().storeInMemoryDynamic(*arrayType.baseType(), true);
}

m_context << Instruction::POP;
}
else
Expand Down Expand Up @@ -1532,7 +1532,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
{
CompilerContext::LocationSetter locationSetter(m_context, _literal);
TypePointer type = _literal.annotation().type;

switch (type->category())
{
case Type::Category::RationalNumber:
Expand Down Expand Up @@ -1633,13 +1633,13 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty
switch (_operator)
{
case Token::Add:
m_context << Instruction::ADD;
m_context << (c_isSigned ? Instruction::SADD : Instruction::ADD);
break;
case Token::Sub:
m_context << Instruction::SUB;
m_context << (c_isSigned ? Instruction::SSUB : Instruction::SUB);
break;
case Token::Mul:
m_context << Instruction::MUL;
m_context << (c_isSigned ? Instruction::SMUL : Instruction::MUL);
break;
case Token::Div:
case Token::Mod:
Expand Down

0 comments on commit a4be6e1

Please sign in to comment.