kernel: Avoid an out-of-range shift in CopyBits - #6534
Merged
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #6534 +/- ##
==========================================
- Coverage 78.98% 78.97% -0.01%
==========================================
Files 684 684
Lines 294205 294226 +21
Branches 8647 8678 +31
==========================================
+ Hits 232370 232377 +7
- Misses 60028 60034 +6
- Partials 1807 1815 +8 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
CopyBits and its helpers shift by amounts derived from <frombit>, <tobit> and the alignment difference between the two blocks. Several of those can reach BIPEB, where `1 << BIPEB` and `x >> BIPEB` are undefined: * After a partial first destination word is filled, <frombit> can be left equal to BIPEB rather than wrapping to the next source word. MaskForCopyBits then evaluates `(UInt)1 << BIPEB`. * In the main loop <frombit> equal to 0 makes the second half of the word assembly shift by `BIPEB - 0`. * CopyInWord shifts by <shift>. The callers do keep it in range, but only indirectly: in the `tobit + BIPEB - frombit` case it takes the branch condition `frombit + tailbits > BIPEB` to show frombit > tobit. Normalise <frombit> to the start of the next word, make MaskForCopyBits total so an out-of-range bound yields an empty mask, special-case the aligned main loop, and bound the shift in CopyInWord directly. An exhaustive sweep over frombit, tobit in [0,BIPEB) and nbits in [1,5*BIPEB] hits the undefined shift in 1953 of 1310720 cases, and gives identical results before and after: in every one of those cases the mask being computed is dead, because no whole words remain to copy. So this changes no observable behaviour on current compilers. The guards also do a second job. They are what lets a static analyzer establish the bounds: without them clang's core.BitwiseShift reports "Left shift overflows the capacity of 'UInt'" for paths reaching here from blister.c and vecgf2.c. Please keep them even where a local reading suggests the branch is dead. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
fingolfin
force-pushed
the
mh/fix-CopyBits
branch
from
August 30, 2026 15:37
6607626 to
77a2746
Compare
lgoettgens
approved these changes
Aug 31, 2026
lgoettgens
left a comment
Member
There was a problem hiding this comment.
I don't understand all the nitty bitty details, but looks sensible overall
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CopyBits and its helpers shift by amounts derived from
<frombit>,<tobit>and the alignment difference between the two blocks. Several of those can reach BIPEB, where1 << BIPEBandx >> BIPEBare undefined:<frombit>can be left equal to BIPEB rather than wrapping to the next source word. MaskForCopyBits then evaluates(UInt)1 << BIPEB.<frombit>equal to 0 makes the second half of the word assembly shift byBIPEB - 0.<shift>. The callers do keep it in range, but only indirectly: in thetobit + BIPEB - frombitcase it takes the branch conditionfrombit + tailbits > BIPEBto show frombit > tobit.Normalise
<frombit>to the start of the next word, make MaskForCopyBits total so an out-of-range bound yields an empty mask, special-case the aligned main loop, and bound the shift in CopyInWord directly.An exhaustive sweep over frombit, tobit in [0,BIPEB) and nbits in [1,5*BIPEB] hits the undefined shift in 1953 of 1310720 cases, and gives identical results before and after: in every one of those cases the mask being computed is dead, because no whole words remain to copy. So this changes no observable behaviour on current compilers.
The guards also do a second job. They are what lets a static analyzer establish the bounds: without them clang's core.BitwiseShift reports "Left shift overflows the capacity of 'UInt'" for paths reaching here from blister.c and vecgf2.c. Please keep them even where a local reading suggests the branch is dead.
Co-authored-by: Claude Opus 5 noreply@anthropic.com