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

Produce compiler error for compound division and mod zero operations #15074

Conversation

clonker
Copy link
Member

@clonker clonker commented May 2, 2024

Fixes #14702

As a side-effect, this will change the place in which an error for expressions of the form a = a / 0 is raised:

  • in terms of types, such expressions yield an IntegerType on the left-hand side, so no explicit value is associated with it as well
  • pretending the lhs to be 0 lets me reuse some of the functionality but it also doesn't 100%ly capture the nature of the problem ("unary f: x->x/0 is bad")
  • without this change, an error for a=a/0 will be raised in static analyzer. Static analyzer states in its docs, that it has to be possible to write equivalent code that does not generate the warning, so perhaps it was not the right place for raising it to begin with?

Copy link
Member

@r0qs r0qs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @clonker thanks a lot for your contribution. I have some initial comments :)

libsolidity/ast/Types.cpp Outdated Show resolved Hide resolved
libsolidity/ast/Types.cpp Outdated Show resolved Hide resolved
libsolidity/ast/Types.cpp Outdated Show resolved Hide resolved
@clonker clonker force-pushed the 14702-produce-compiler-error-compound-div-mod-zero branch 2 times, most recently from f5a6e41 to d114346 Compare May 6, 2024 11:58
Comment on lines 742 to 745
else if (_operator == Token::Mod || _operator == Token::Div)
if (_other->category() == Type::Category::RationalNumber)
if (dynamic_cast<RationalNumberType const*>(_other)->value().numerator() == 0)
return nullptr;
Copy link
Member

@ekpyron ekpyron May 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you actually in your call earlier conclude that this is the better option :-)? I'd have expected us to just add an analog case to the existing Division by/Modulo zero errors (with those as error messages) in the Assignment visitor of the StaticAnalyzer (but I'm mainly being curious here - for this change I'd need to check, if it actually affects anything else and am surprised that it doesn't e.g. also change the error message for existing / 0 cases and such)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We mainly concluded that doing it here produces the same error and in the same cases as the % and / case, so it should be fine.

Now that you mention it, I haven't actually looked at the place where % and / are handled currently. But I don't think this is done in StaticAnalyzer. Or is it? Will have to check in the final review.

Copy link
Member

@ekpyron ekpyron May 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(_operation.getOperator() == Token::Div) ? "Division by zero." : "Modulo zero."

I actually also now realized why this change doesn't change the error message in the test for this error: in the test case it's actually an expression on literals there (or well, constants - which are treated as literals).

Anyways - since I also now read in the PR description:

Static analyzer states in its docs, that it has to be possible to write equivalent code that does not generate the warning, so perhaps it was not the right place for raising it to begin with?

The equivalent code in these cases is revert(); - since that's what a division by zero does :-).

But yeah, none of this matters too much, this was just a random issue to get started anyways.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, that also explains why we have this weird error in the first place: it wasn't ever meant to apply for runtime divisions, but only for compile-time divisions (and divisions of constants, which are compile-time divisions).

So given that, actually, the better fix here, is in fact (as @cameel, you suggested earlier today in chat) to do the opposite and allow this for runtime division.

Which should be doable by just adding

*_operation.leftExpression().annotation().isPure &&
ConstantEvaluator::evaluate(m_errorReporter, _operation.leftExpression())) &&

to the condition in

*_operation.rightExpression().annotation().isPure &&

That should still catch divisions by zero on compile-time evaluated constants - but leave uint x; x / 0; in peace - and we also solved the inconsistency, since /= 0 is impossible for compile-time constants.

So I'd suggest we just do that instead - but yeah, this was actually a rather weird issue that I picked at random here :-D. The lesson to be learned is: never blindly do exactly what people ask ;-).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it's a different issue in a sense, I feel like having a warning regarding div / mod zero (also for compounds) isn't such a bad thing and wouldnt introduce inconsistencies. But yeah, a bit weird :-D

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it's a different issue in a sense, I feel like having a warning regarding div / mod zero (also for compounds) isn't such a bad thing and wouldn't introduce inconsistencies. But yeah, a bit weird :-D

In principle: yes.
The problem is, that we can't do it well anyways - we don't have full compile-time-constant expression evaluation.
So you'd get a warning for

uint x; x / 0;

but not for

uint x = 1; uint y = 1; uint z;
z / (x - y);

So in the end just for the boring and obvious cases - which is arguably worse than not at all...
Conversely, proper compile-time-constant expression evaluation would be nice of course, but also quite a bit of effort, especially since it'd need to match EVM semantics completely accurately.

@ethereum ethereum deleted a comment from github-actions bot May 6, 2024
@clonker clonker force-pushed the 14702-produce-compiler-error-compound-div-mod-zero branch 4 times, most recently from bd65a0f to f25ef43 Compare May 7, 2024 09:06
Changelog.md Outdated Show resolved Hide resolved
nikola-matic
nikola-matic previously approved these changes May 7, 2024
@clonker clonker force-pushed the 14702-produce-compiler-error-compound-div-mod-zero branch from f25ef43 to dd07096 Compare May 7, 2024 09:54
Changelog.md Show resolved Hide resolved
@clonker clonker merged commit aa6bbc2 into ethereum:develop May 7, 2024
72 checks passed
@clonker clonker deleted the 14702-produce-compiler-error-compound-div-mod-zero branch May 7, 2024 11:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Division and Modulo by Zero does not produce Compiler Error when using shorthand notation /= and %=
5 participants