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

Exception on overflow #796

Closed
phiferd opened this issue Aug 2, 2016 · 35 comments
Closed

Exception on overflow #796

phiferd opened this issue Aug 2, 2016 · 35 comments
Labels
breaking change ⚠️ language design :rage4: Any changes to the language, e.g. new features

Comments

@phiferd
Copy link

phiferd commented Aug 2, 2016

It would be nice if Solidity, by default, threw an exception for arithmetic overflow, rather than allowing it.

Justification:

  1. Overflow is rarely desired behavior and is commonly cited as a security vulnerability.
    2: Even in cases where overflow is desired behavior, throwing an exception is a far safer failure mode and easier to detect/correct.
    3: The goal of solidity, as I understand it, is to enable the creation of secure and reliable smart contacts. Therefore, although it is of course possible for the developer to include their own checks, including this as a feature of the language will make the common case both simple and more secure.

If this is not achievable, I welcome alternatives that do not require each and every developer to remember these corner cases for each and every arithmetic operation. A solution that states "everybody should do XYZ" will inevitably lead to failures.

I'm am not familiar enough with the code to propose a detailed solution. However, a compiler switch that is on by default and can be disabled for backward compatibility is the sort of approach I was imagining.

@chriseth
Copy link
Contributor

chriseth commented Aug 2, 2016

The main Problem I see with this is that you still have to aware of the possibility of an arithmetic overflow. If we throw in that case, this could stall a smart contract.

The only solution I see is to use our formal verification system that automatically verifies whether overflow protection checks are in place (or not needed).

@phiferd
Copy link
Author

phiferd commented Aug 2, 2016

Could the same argument be made for the exception that is thrown for division by 0 and a negative array index? Those could have the same effect, but I can't see arguing that coming up with some default but incorrect behavior would be better (e.g. We could just wrap array indices around).

My concern is that the failures that can come from overflow go undetected.

I am definitely not suggesting that formal verification should not be done, there is no substitute. But I think allowing overflow offers no real advantage, unless you're hoping to hack a contract.

@chriseth
Copy link
Contributor

chriseth commented Aug 2, 2016

You have a valid point. Still, I think these are not exactly comparable:
Invalid array access and division by zero are more predictable and less "continuous" than arithmetic overflow.

But yes, it is probably better to stall a contract in case of overflow than to provoke undesired effects on state.

What are cases where overflow is actually desired? I think for most of them, we can still use mulmod and addmod.

@chriseth
Copy link
Contributor

Note that this is quite expensive to do, especially for types shorter than 256 bits.

@rainbreak
Copy link
Contributor

Would you consider this for 0.4.0, or is it a bit involved for that?

@ethernomad
Copy link
Contributor

Maybe this should be implemented in the EVM?

@axic
Copy link
Member

axic commented Aug 29, 2016

I think arithmetic overflow detection belongs to the EVM, but that would be a rather big change to it.

@rainbreak
Copy link
Contributor

For the EVM I think it would need extra opcodes as overflowing math is still useful. In the meantime we can have it in Solidity and get the safety benefits at the expense of a bit of gas (completely worth it I think because you end up checking it in safe code anyway).

@chriseth
Copy link
Contributor

@rainbeam This is too involved for 0.4.0. Arithmetics is almost for free when compared to storage writes or even a transaction, so I think it is fine to do it. I do not really agree that this belongs to the EVM. Something like an overflow flag might be added to the EVM, but not a "force-stop" on overflow.

@axic
Copy link
Member

axic commented Aug 30, 2016

I think arithmetic overflow detection belongs to the EVM

By detection I meant the overflow flag. So perhaps that would then needs its on opcode for getting the overflow flag onto the stack and/or its own jump (JUMPOF).

@chriseth
Copy link
Contributor

@pirapira Can you please list all these other issues as tasks for this issue and close the others, or do you think that each issues is a substantial amount of work?

@pirapira
Copy link
Member

pirapira commented Oct 13, 2016

The main reason I opened separate issues is that each requires discussion if we want it or not, but if we are set to go over everything, here is a list.

  • exception on overflow in unsigned->signed conversion
  • exception on overflow in signed->unsigned conversion
  • exception on overflow in size-decreasing implicit conversion
  • exception on overflow in addition of two signed numbers
  • exception on overflow in addition of two unsigned numbers
  • exception on underflow in subtraction of two signed numbers
  • exception on underflow in subtraction of two unsigned numbers
  • exception on overflow in multiplication of two signed numbers
  • exception on overflow in multiplication of two unsigned numbers
  • exception on overflow in shifts
  • exception on overflow in ++ on a signed number
  • exception on overflow in ++ on an unsigned number
  • exception on underflow in -- on a signed number
  • exception on underflow in -- on an unsigned number
  • exception on overflow in +=
  • exception on overflow in -=
  • exception on overflow in *=
  • exception on overflow in /=
  • make sure no optimizations are relying on (a + b - b == a); lest they remove overflow exceptions
  • compiler error on an out-of-range constant expression when the constant expression is interpreted into a type (uint x = -1)
  • exception on overflow in INT_MIN/-1 Breaking: overflow detection for SDIV - minInt / (-1) #1091
  • exponentiation

@ethers
Copy link
Member

ethers commented Dec 20, 2016

This is labelled "soon" and how soon will this be? :) Does the long checklist need to be implemented at once, or can it be done iteratively?
Implementing some of them can already provide early safety/ROI imo, like:

  • exception on overflow in addition of two unsigned numbers
  • exception on underflow in subtraction of two unsigned numbers

@ethers
Copy link
Member

ethers commented Dec 20, 2016

@pirapira In your checklist, exception on overflow in /= is duplicated. I think for one of them you mean exception on underflow in -=.

Also, how about overflow of INT_MIN/-1 ?

@pirapira
Copy link
Member

@ethers Thank you. I fixed the checklist above.

These overflow checkings are breaking changes, and for some reasons, Solidity release 0.5.0 will be the next one that can contain breaking changes. I would support removing this rule (until we get to 1.0.0).

@MicahZoltu
Copy link
Contributor

MicahZoltu commented Jun 30, 2017

If Solidity doesn't already do this, a line item in the TODO list should be added for truncation during assignment.

uint16 a = 2^15;
uint8 b = a;

@chriseth
Copy link
Contributor

@axic yes, an unchecked region where also the SMT checker is disabled is certainly a good idea. Whether we can enable runtime checks by default in the non-unchecked areas should also depend on an assessment about how well the optimizer can handle such cases, and perhaps an improvement in that area.

@phiferd
Copy link
Author

phiferd commented Apr 26, 2018

The recently discovered overflow on batchTransfer in some ERC20 contracts is a good example of the type of issue that could be avoided if this is implemented.

https://medium.com/@peckshield/alert-new-batchoverflow-bug-in-multiple-erc20-smart-contracts-cve-2018-10299-511067db6536

@axic
Copy link
Member

axic commented Apr 26, 2018

For the syntax (mentioned in #796 (comment)) I propose:

unchecked "overflow" {
  a = b + c;
}

It follows the same syntax as not-so-well-known syntax of the assembly keyword: assembly "evmasm" {}

@chriseth
Copy link
Contributor

@axic yep, exactly my thought, that allows us to introduce other checks in the same way later.

@axic
Copy link
Member

axic commented Apr 26, 2018

that allows us to introduce other checks in the same way later.

That was my motivation :)

@kumavis
Copy link
Member

kumavis commented Apr 26, 2018

@axic what about making the current math operators safe and adding new operators for non-safe math

c = a + b // safe
c = a %+ b // non-safe

pick whatever symbol works, i chose %+ to imply modular arithmetic

Edit:
I guess this would not handle the conversion cases (e.g. signed->unsigned)
And the generic check-modifying block opens up interesting possibilities

@axic axic added language design :rage4: Any changes to the language, e.g. new features and removed breaking for 0.5.0 labels Jul 28, 2018
@axic axic removed this from the 2-breaking-safety-changes milestone Jul 30, 2018
@axic axic removed the soonish label Jul 30, 2018
@rocky
Copy link
Contributor

rocky commented Aug 18, 2018

In #796 (comment) I think there is one more case not mentioned, exponentiation.

@johnsoncarl
Copy link

johnsoncarl commented May 22, 2019

The main reason I opened separate issues is that each requires discussion if we want it or not, but if we are set to go over everything, here is a list.

  • exception on overflow in unsigned->signed conversion
  • exception on overflow in signed->unsigned conversion
  • exception on overflow in size-decreasing implicit conversion
  • exception on overflow in addition of two signed numbers
  • exception on overflow in addition of two unsigned numbers
  • exception on underflow in subtraction of two signed numbers
  • exception on underflow in subtraction of two unsigned numbers
  • exception on overflow in multiplication of two signed numbers
  • exception on overflow in multiplication of two unsigned numbers
  • exception on overflow in shifts
  • exception on overflow in ++ on a signed number
  • exception on overflow in ++ on an unsigned number
  • exception on underflow in -- on a signed number
  • exception on underflow in -- on an unsigned number
  • exception on overflow in +=
  • exception on overflow in -=
  • exception on overflow in *=
  • exception on overflow in /=
  • make sure no optimizations are relying on (a + b - b == a); lest they remove overflow exceptions
  • compiler error on an out-of-range constant expression when the constant expression is interpreted into a type (uint x = -1)
  • exception on overflow in INT_MIN/-1 Breaking: overflow detection for SDIV - minInt / (-1) #1091
  • exponentiation

How many of these are completed till now?

@chriseth
Copy link
Contributor

@johnsoncarl we are implementing this along with the transition to yul as an intermediate language. The reason is that we hope that the yul optimizer can better cope with all the additional checks that are introduced and complicate the control-flow. It is still not 100% clear if we really want that on explicit type conversions. It is implemented (or at least PRs in progress) for increment, decrement, unsigned multiplication and addition.

@chriseth
Copy link
Contributor

We are thinking of using the existing yul implementation and adding it to 0.7.0.

@chriseth
Copy link
Contributor

Implemented in #9465

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking change ⚠️ language design :rage4: Any changes to the language, e.g. new features
Projects
None yet
Development

No branches or pull requests