-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Fix overflow when initializing a Sieve with T::MAX #47
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #47 +/- ##
=======================================
Coverage 99.32% 99.33%
=======================================
Files 9 9
Lines 1340 1344 +4
=======================================
+ Hits 1331 1335 +4
Misses 9 9 ☔ View full report in Codecov by Sentry. |
.expect("addition should not overflow by construction"); | ||
if self.safe_primes { | ||
num = num.wrapping_shl_vartime(1) | T::one_like(&self.base); | ||
match self.base.checked_add(&self.incr.into()).into_option() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like here we're branching on something that will never happen unless the private attributes are messed with? Also, instead of returning None
for a composite now the method returns None
for a composite or if there's an overflow, which can be confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This overflow can actually happen without any malicious shenanigans (and is guarded against with the sieve_with_max_start
test).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with you about the odd control flow here though. It gets complex quick:
- Create a sieve and set
base
toT::MAX
(like the test). - Call
next()
- The first call to
update_residues()
will work fine becauseincr
== 0 (returns true) - …but this first call will set
last_round
to true as a side effect. - Now we call
maybe_next()
which will also work fine becauseT::MAX
is composite (returns None) - …but now
incr
andincr_limit
are 2 as a side effect. - We call
update_residues
again, and given thatincr
is now 2 and less or equal toincr_limit
, we match on the first check and returntrue
(note:last_round
is true, which would cause returning false) - So now we call
maybe_next
again but now the addition overflows so we returnNone
and the main loopcontinue
s - Back in
update_residues()
for the third time, we finally hit the check forlast_round
, so we return false - …which causes the main
while
-loop innext()
to exit and we returnNone
- …and the iterator stops.
Pheew!!!
Maybe the Sieve constructor should check if the given start
is worth the effort? E.g. check if T::MAX - start
contains "enough" primes. Maybe using PNT and check that T::MAX/log(T::MAX) - start/log(start)
is larger than some number (1?, 10?)? Or can you think of something smarter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
…then again, there are a lot of primes, so even if they pick a start that is 99.999999% of T::MAX
there are still a LOT of prime candidates left, so maybe we just check that start != T::MAX
and that's good enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't particularly like the idea of heuristic checks and relying on probabilities in this specific case (the sieve), I think if it's possible to do exactly, we should try to do it.
Now we call maybe_next() which will also work fine because T::MAX is composite
Not necessarily, 2^128-1 and 2^8192-1 are primes. (Actually the former can be used as a test)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Actually the former can be used as a test)
You mean 2^127 -1? Is that the last prime before U128::MAX, probably not right? Seems like a bit of an arbitrary test, or maybe I'm misunderstanding what you're suggesting here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, my mistake. Any 2^n-1
is indeed composite if n
is composite.
@fjarri I think this one is ready to go in. I'd prefer to do any bigger refactoring of the sieve in a different PR (if we deem it's worth our time). |
Avoids a panic when initializing a
Sieve
withT::MAX
.