libstdc++: Avoid overflow in ranges::advance(i, n, bound)
authorJonathan Wakely <jwakely@redhat.com>
Wed, 26 Jan 2022 16:08:51 +0000 (16:08 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Thu, 27 Jan 2022 22:24:29 +0000 (22:24 +0000)
commitf21f22d1baf7e90f3edbfc48040c76fb14103803
tree73188c6f671ab823be094485ebad7a562b5caa29
parent66b86171188dcb61d2d0e0a4a98a7467e58a84a7
libstdc++: Avoid overflow in ranges::advance(i, n, bound)

When (bound - i) or n is the most negative value of its type, the
negative of the value will overflow. Instead of abs(n) >= abs(bound - i)
use n >= (bound - i) when positive and n <= (bound - i) when negative.
The function has a precondition that they must have the same sign, so
this works correctly. The precondition check can be moved into the else
branch, and simplified.

The standard requires calling ranges::advance(i, bound) even if i==bound
is already true, which is technically observable, but that's pointless.
We can just return n in that case. Similarly, for i!=bound but n==0 we
are supposed to call ranges::advance(i, n), but that's pointless. An LWG
issue to allow omitting the pointless calls is expected to be filed.

libstdc++-v3/ChangeLog:

* include/bits/ranges_base.h (ranges::advance): Avoid signed
overflow. Do nothing if already equal to desired result.
* testsuite/24_iterators/range_operations/advance_overflow.cc:
New test.
libstdc++-v3/include/bits/ranges_base.h
libstdc++-v3/testsuite/24_iterators/range_operations/advance_overflow.cc [new file with mode: 0644]