Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Checked arithmetic by default. #9465

Merged
merged 5 commits into from Oct 19, 2020
Merged

Checked arithmetic by default. #9465

merged 5 commits into from Oct 19, 2020

Conversation

@chriseth
Copy link
Contributor

@chriseth chriseth commented Jul 22, 2020

Depends on #9479.

TODO:

  • documentation
  • document: division by zero is always checked
  • wrapping arithmetics for Sol -> Yul
  • disallow -x for unsigned x outside of "unchecked" - or do we want to disallow it in general? 0-x is still OK, I would say.
  • decide which error to report and change all errors.
@chriseth chriseth force-pushed the unchecked branch from ed72489 to fc31877 Jul 22, 2020
libsolidity/codegen/CompilerContext.h Outdated Show resolved Hide resolved
libsolidity/codegen/ContractCompiler.cpp Outdated Show resolved Hide resolved
libsolidity/codegen/ContractCompiler.cpp Outdated Show resolved Hide resolved
libsolidity/ast/AST.h Outdated Show resolved Hide resolved
@stackenbotten
Copy link

@stackenbotten stackenbotten commented Jul 22, 2020

There was an error when running chk_coding_style for commit d4651d289c3a790a5a8bb0d9b1818762e9a06788:

Error: Trailing whitespace found:
 libsolidity/ast/AST.h:1341: Statement(_id, _location, _docString), 

Please check that your changes are working as intended.

@stackenbotten
Copy link

@stackenbotten stackenbotten commented Jul 22, 2020

There was an error when running chk_coding_style for commit 84ac4987282254e1782946313163dcf202c6d5e7:

Error: Trailing whitespace found:
 libsolidity/ast/AST.h:1341: Statement(_id, _location, _docString), 

Please check that your changes are working as intended.

@chriseth chriseth force-pushed the unchecked branch from d4651d2 to 44e18bc Jul 23, 2020
@stackenbotten
Copy link

@stackenbotten stackenbotten commented Jul 23, 2020

There was an error when running chk_coding_style for commit 44e18bc91be7005599bed9f3c05118fb37082fd2:

Error: Trailing whitespace found:
 libsolidity/ast/AST.h:1341: Statement(_id, _location, _docString), 

Please check that your changes are working as intended.

@leonardoalt
Copy link
Member

@leonardoalt leonardoalt commented Jul 23, 2020

Rebase problems?

@axic
Copy link
Member

@axic axic commented Aug 5, 2020

This still needs to be rebased and perhaps need to merge develop into breaking too. At the same time this seems to depend on #9479, so I'd suggest turning this to draft until that is merged.

@axic axic marked this pull request as draft Aug 5, 2020
@chriseth chriseth force-pushed the unchecked branch from 44e18bc to b367415 Aug 6, 2020
@stackenbotten
Copy link

@stackenbotten stackenbotten commented Aug 6, 2020

There was an error when running chk_coding_style for commit b3674152aa040dd440da1143a07ce8522eeda451:

Error: Trailing whitespace found:
 libsolidity/ast/AST.h:1341: Statement(_id, _location, _docString), 

Please check that your changes are working as intended.

@chriseth chriseth changed the base branch from breaking to breaking_8 Aug 6, 2020
@chriseth
Copy link
Contributor Author

@chriseth chriseth commented Aug 6, 2020

Rebased and changed target to breaking_8 (@axic requested to have one breaking branch per release at some point)

@chriseth chriseth force-pushed the unchecked branch from b367415 to c24cc01 Sep 14, 2020
@chriseth chriseth changed the base branch from breaking_8 to breaking Sep 14, 2020
@stackenbotten
Copy link

@stackenbotten stackenbotten commented Sep 14, 2020

There was an error when running chk_coding_style for commit c24cc01f404d3796f672cdbcd89211dac987f18c:

Error: Trailing whitespace found:
 libsolidity/ast/AST.h:1347: Statement(_id, _location, _docString), 

Please check that your changes are working as intended.

@chriseth chriseth force-pushed the unchecked branch 8 times, most recently from 38be2ad to e7e6212 Sep 15, 2020
@chriseth chriseth force-pushed the unchecked branch 5 times, most recently from 8450cc3 to 2b3900d Sep 23, 2020
@chriseth chriseth force-pushed the unchecked branch 3 times, most recently from 709edb0 to a991b2f Oct 12, 2020
block:
LBrace ( statement | uncheckedBlock )* RBrace;

uncheckedBlock: Unchecked block;

This comment has been minimized.

@leonardoalt

leonardoalt Oct 14, 2020
Member

This allows for nested unchecked blocks.

This comment has been minimized.

@chriseth

chriseth Oct 15, 2020
Author Contributor

Yes, it is not a parser but a syntax checker restriction.

This comment has been minimized.

@ekpyron

ekpyron Oct 15, 2020
Member

Is if (<sth>) unchecked { x; } invalid? (I'll probably know when I'm done reviewing...)

This comment has been minimized.

@ekpyron

ekpyron Oct 15, 2020
Member

Yeah, apparently it isn't - not sure if it couldn't be valid, but fine!

There are two modes in which arithmetic is performed on these types: The "wrapping" or "unchecked" mode and the "checked" mode.
By default, arithmetic is always "checked", which mean that if the result of an operation falls outside the value range
of the type, the call is reverted through a :ref:`failing assertion<assert-and-require>`. You can switch to "unchecked" mode
using ``unchecked { ... }``. More details can be found in the section about <unchecked>.

This comment has been minimized.

@leonardoalt

leonardoalt Oct 14, 2020
Member

Is <unchecked> at the end an actual link to the section?

This comment has been minimized.

@chriseth

chriseth Oct 15, 2020
Author Contributor

nope, it's not. Will fix.

modes in regard to over- and underflow:

By default, all arithmetic is checked for under- or overflow, but this can be disabled
using the <unchecked> block, resulting in wrapping arithmetic. More details

This comment has been minimized.

@leonardoalt

leonardoalt Oct 14, 2020
Member

Suggested change
using the <unchecked> block, resulting in wrapping arithmetic. More details
using the <unchecked> block, resulting in modular arithmetic. More details

This comment has been minimized.

@leonardoalt

leonardoalt Oct 14, 2020
Member

Is <unchecked> a link?

This comment has been minimized.

@chriseth

chriseth Oct 15, 2020
Author Contributor

Fixed the link. Rust also uses the term "wrapping": https://doc.rust-lang.org/std/primitive.u32.html#method.wrapping_add

Maybe "wrapping" is also less intimidating than "modular"?

@@ -380,6 +384,8 @@ class CompilerContext
std::map<Declaration const*, std::vector<unsigned>> m_localVariables;
/// The contract currently being compiled. Virtual function lookup starts from this contarct.
ContractDefinition const* m_mostDerivedContract = nullptr;
/// Whether to use checked arithmetic.
std::stack<Arithmetic> m_arithmetic;

This comment has been minimized.

@leonardoalt

leonardoalt Oct 14, 2020
Member

It needs to be a stack because you can call a function inside an unchecked block and then open another unchecked block inside that function, but the rest of that function is checked. Correct?

This comment has been minimized.

@chriseth

chriseth Oct 14, 2020
Author Contributor

It actually does not need to be a stack anymore, I think.

@chriseth chriseth force-pushed the unchecked branch from 4d1b441 to 71723aa Oct 15, 2020
Copy link
Member

@ekpyron ekpyron left a comment

I haven't seen anything that really bothered me in the first pass, but I wasn't extremely careful about it, so I'm a bit hesitant approving just yet...

An overflow or underflow is the situation where the resulting value of an arithmetic operation,
when executed on an unrestricted integer, falls outside the range of the result type.
Comment on lines 519 to 520

This comment has been minimized.

@ekpyron

ekpyron Oct 15, 2020
Member

This seems a bit out of place to me here... this should probably be the second paragraph of the section at the very top?

block:
LBrace ( statement | uncheckedBlock )* RBrace;

uncheckedBlock: Unchecked block;

This comment has been minimized.

@ekpyron

ekpyron Oct 15, 2020
Member

Is if (<sth>) unchecked { x; } invalid? (I'll probably know when I'm done reviewing...)

block:
LBrace ( statement | uncheckedBlock )* RBrace;

uncheckedBlock: Unchecked block;

This comment has been minimized.

@ekpyron

ekpyron Oct 15, 2020
Member

Yeah, apparently it isn't - not sure if it couldn't be valid, but fine!

@@ -460,7 +479,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
m_context << commonType->literalValue(nullptr);
else
{
bool cleanupNeeded = cleanupNeededForOp(commonType->category(), c_op);
bool cleanupNeeded = m_context.arithmetic() == Arithmetic::Checked || cleanupNeededForOp(commonType->category(), c_op);

This comment has been minimized.

@ekpyron

ekpyron Oct 15, 2020
Member

Do we actually need cleanup here or aren't we doing it twice then? The checked arithmetic yul functions do the cleanup themselves, don't they?

This comment has been minimized.

@chriseth

chriseth Oct 15, 2020
Author Contributor

true!

@chriseth
Copy link
Contributor Author

@chriseth chriseth commented Oct 15, 2020

if (<sth>) unchecked { x; } is invalid currently. It was just looking weird to me. We anyway need a special case unless we also want
function f() public unchecked { x; } to be valid.

@ekpyron
Copy link
Member

@ekpyron ekpyron commented Oct 15, 2020

if (<sth>) unchecked { x; } is invalid currently. It was just looking weird to me. We anyway need a special case unless we also want
function f() public unchecked { x; } to be valid.

It's fine, I was just wondering when I saw the grammar - disallowing it now is definitely good - we can still allow it later anyways, while not the other way!

@chriseth chriseth force-pushed the unchecked branch from 324e097 to 1f6b173 Oct 15, 2020
Copy link
Member

@leonardoalt leonardoalt left a comment

A few small comments.

It would be nice to also have a few more corner case tests:

  • unchecked function called by checked function called by unchecked function
  • checked function called by unchecked function
  • is it possible to have contract C { uint x = unchecked { ... }; } ?
@@ -275,7 +275,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
solAssert(*_assignment.annotation().type == leftType, "");
bool cleanupNeeded = false;
if (op != Token::Assign)
cleanupNeeded = cleanupNeededForOp(leftType.category(), binOp);
cleanupNeeded = m_context.arithmetic() == Arithmetic::Checked || cleanupNeededForOp(leftType.category(), binOp);

This comment has been minimized.

@leonardoalt

leonardoalt Oct 16, 2020
Member

Is this just extra safety?

This comment has been minimized.

@ekpyron

ekpyron Oct 16, 2020
Member

Same as #9465 (comment) - since the arithmetic functions in yul already do the cleanup, we should probably not clean up before them.

});
}


This comment has been minimized.

@leonardoalt

leonardoalt Oct 16, 2020
Member

Extra blank

break;
case Token::Mod:
fun = m_utils.checkedIntModFunction(*type);
fun = m_utils.intModFunction(*type);

This comment has been minimized.

@leonardoalt

leonardoalt Oct 16, 2020
Member

What about exp?

This comment has been minimized.

@chriseth

chriseth Oct 19, 2020
Author Contributor

It branches out earlier in visit(BinaryOperation const& _binOp)

BOOST_CHECK(TokenTraits::isReservedKeyword(Token::Var));
BOOST_CHECK(TokenTraits::isReservedKeyword(Token::Reference));

This comment has been minimized.

@leonardoalt

leonardoalt Oct 16, 2020
Member

Where did Reference come from?

This comment has been minimized.

@ekpyron

ekpyron Oct 16, 2020
Member

IIUC the test verifies that isReservedKeyword is correctly true for the first and the last reserved keyword - the last one used to be unchecked, but then we made var reserved again and added it as new last one here, but just kept unchecked, so since then the idea is "check first and last reserved keyword and a random one in between" - the random one in between can't be unchecked anymore, so now it's reference...

@leonardoalt
Copy link
Member

@leonardoalt leonardoalt commented Oct 19, 2020

Actually some commits need to be squashed.

@chriseth chriseth force-pushed the unchecked branch from 37fc84b to c9ef727 Oct 19, 2020
@leonardoalt
Copy link
Member

@leonardoalt leonardoalt commented Oct 19, 2020

Looks good. What about decide which error to report and change all errors.?

@chriseth
Copy link
Contributor Author

@chriseth chriseth commented Oct 19, 2020

Will be done in #10013

@chriseth chriseth merged commit 33a5fbf into breaking Oct 19, 2020
40 checks passed
40 checks passed
ci/circleci: b_archlinux Your tests passed on CircleCI!
Details
ci/circleci: b_bytecode_ems Your tests passed on CircleCI!
Details
ci/circleci: b_bytecode_osx Your tests passed on CircleCI!
Details
ci/circleci: b_bytecode_ubu Your tests passed on CircleCI!
Details
ci/circleci: b_bytecode_win Your tests passed on CircleCI!
Details
ci/circleci: b_docs Your tests passed on CircleCI!
Details
ci/circleci: b_ems Your tests passed on CircleCI!
Details
ci/circleci: b_osx Your tests passed on CircleCI!
Details
ci/circleci: b_ubu Your tests passed on CircleCI!
Details
ci/circleci: b_ubu18 Your tests passed on CircleCI!
Details
ci/circleci: b_ubu_clang Your tests passed on CircleCI!
Details
ci/circleci: b_ubu_cxx20 Your tests passed on CircleCI!
Details
ci/circleci: b_ubu_ossfuzz Your tests passed on CircleCI!
Details
ci/circleci: b_ubu_release Your tests passed on CircleCI!
Details
ci/circleci: b_win Your tests passed on CircleCI!
Details
ci/circleci: b_win_release Your tests passed on CircleCI!
Details
ci/circleci: chk_antlr_grammar Your tests passed on CircleCI!
Details
ci/circleci: chk_buglist Your tests passed on CircleCI!
Details
ci/circleci: chk_coding_style Your tests passed on CircleCI!
Details
ci/circleci: chk_docs_pragma_min_version Your tests passed on CircleCI!
Details
ci/circleci: chk_errorcodes Your tests passed on CircleCI!
Details
ci/circleci: chk_proofs Your tests passed on CircleCI!
Details
ci/circleci: chk_pylint Your tests passed on CircleCI!
Details
ci/circleci: chk_spelling Your tests passed on CircleCI!
Details
ci/circleci: t_archlinux_soltest Your tests passed on CircleCI!
Details
ci/circleci: t_bytecode_compare Your tests passed on CircleCI!
Details
ci/circleci: t_ems_compile_ext_colony Your tests passed on CircleCI!
Details
ci/circleci: t_ems_compile_ext_gnosis Your tests passed on CircleCI!
Details
ci/circleci: t_ems_compile_ext_zeppelin Your tests passed on CircleCI!
Details
ci/circleci: t_ems_solcjs Your tests passed on CircleCI!
Details
ci/circleci: t_osx_cli Your tests passed on CircleCI!
Details
ci/circleci: t_osx_soltest Your tests passed on CircleCI!
Details
ci/circleci: t_ubu_clang_soltest Your tests passed on CircleCI!
Details
ci/circleci: t_ubu_cli Your tests passed on CircleCI!
Details
ci/circleci: t_ubu_release_cli Your tests passed on CircleCI!
Details
ci/circleci: t_ubu_release_soltest Your tests passed on CircleCI!
Details
ci/circleci: t_ubu_soltest Your tests passed on CircleCI!
Details
ci/circleci: t_ubu_soltest_enforce_yul Your tests passed on CircleCI!
Details
ci/circleci: t_win Your tests passed on CircleCI!
Details
ci/circleci: t_win_release Your tests passed on CircleCI!
Details
@chriseth chriseth deleted the unchecked branch Oct 19, 2020
@chriseth chriseth mentioned this pull request Oct 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

8 participants
You can’t perform that action at this time.