-
Notifications
You must be signed in to change notification settings - Fork 1.6k
<algorithm>
: Avoid integer overflow in stable_sort()
and ranges::stable_sort
for huge inputs on x86
#5677
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
<algorithm>
: Avoid integer overflow in stable_sort()
and ranges::stable_sort
for huge inputs on x86
#5677
Conversation
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.
May be worth adding a comment to _ISORT_MAX
that overflow analysis of stable_sort
depends on it remaining 32==2^5.
Thanks!
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.
Just some suggestions, feel free to push back.
This comment was marked as resolved.
This comment was marked as resolved.
Good catch, that's bogus. It's harder to repro in practice - because we skip over 2 + 4 + 8 + ... elements, we actually handle up to 2 billion. It would require an artificially small iterator difference type (usually only seen in library test suites). It's trivial to express the check properly with |
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.
LGTM, thanks for the clarifying comments.
I'm mirroring this to the MSVC-internal repo - please notify me if any further changes are pushed. |
Reported by Aditya Anand to our internal C++ mailing list.
On x86, it's barely possible for
stable_sort()
to trigger an integer overflow when repeatedly doubling a chunk size. This happens when sorting over a billion 1-byte elements; the test case below uses 2^30 + 2 bytes. Surprisingly, this bug has been present since the beginning of time; we've historically been pretty good about checking for overflow before multiplying (e.g. in geometric growth), but missed this case.We can avoid this integer overflow by testing whether we're done before doubling the chunk size. As the comment explains, I've carefully transformed the test to avoid even/odd issues.
ranges::stable_sort
was equally affected.I'm not altering the initial doubling in this loop. Because we start with 32, i.e. 2^5, the first doubling is always safe (e.g. from 2^29 to 2^30). It's only the second doubling that might overflow (e.g. from 2^30 to 2^31 here). At this time I simply don't care about pathological
_Iter_diff_t
that might have a limit other than a normal power of 2. (Note that this logic still works for 16-bit ultra-narrow difference types; it would have to be extremely pathological for this to be an issue.)Manual Testing
Because this involves allocating an enormous amount of memory, automated test coverage isn't appropriate. I manually tested the fix, and the detailed comments should be sufficient to avoid regressions during future maintenance.
Plain VS 2022 17.14.12 x86 simply crashes:
After this PR:
These tests are compiled with optimizations so they finish in a reasonable amount of time. The behavior is the same, just agonizingly slower, with
/MTd /Od
.