Skip to content

Commit 39444f2

Browse files
committed
big.int.depositBits: fix handling of different limb counts
1 parent 56e2448 commit 39444f2

File tree

2 files changed

+17
-2
lines changed

2 files changed

+17
-2
lines changed

lib/std/math/big/int.zig

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,6 +1763,8 @@ pub const Mutable = struct {
17631763
/// result = @depositBits(source, mask)
17641764
///
17651765
/// Asserts that `source` and `mask` are positive
1766+
/// The value in `result` may use the same number of or less limbs than `mask`.
1767+
/// `result` is assumed to have sufficient length to store the result.
17661768
pub fn depositBits(result: *Mutable, source: Const, mask: Const) void {
17671769
assert(source.positive);
17681770
assert(mask.positive);
@@ -1771,10 +1773,14 @@ pub const Mutable = struct {
17711773
@memset(result.limbs, 0);
17721774

17731775
var shift: usize = 0;
1774-
for (mask.limbs, result.limbs) |mask_limb, *result_limb| {
1776+
for (mask.limbs, 0..) |mask_limb, i| {
17751777
const shift_bits: Log2Limb = @intCast(shift % limb_bits);
17761778
const shift_limbs = shift / limb_bits;
17771779

1780+
if (shift_limbs >= source.limbs.len) break;
1781+
1782+
const result_limb = &result.limbs[i];
1783+
17781784
var source_limb = source.limbs[shift_limbs] >> shift_bits;
17791785
if (shift_bits != 0 and shift_limbs + 1 < source.limbs.len) {
17801786
source_limb += source.limbs[shift_limbs + 1] << @intCast(limb_bits - shift_bits);
@@ -1793,15 +1799,19 @@ pub const Mutable = struct {
17931799
/// result = @extractBits(source, mask)
17941800
///
17951801
/// Asserts that `source` and `mask` are positive
1802+
/// The value in `result` may use the same number of or less limbs than `mask`.
1803+
/// `result` is assumed to have sufficient length to store the result.
17961804
pub fn extractBits(result: *Mutable, source: Const, mask: Const) void {
17971805
assert(source.positive);
17981806
assert(mask.positive);
17991807

18001808
result.positive = true;
18011809
@memset(result.limbs, 0);
18021810

1811+
const len = @min(source.limbs.len, mask.limbs.len);
1812+
18031813
var shift: usize = 0;
1804-
for (source.limbs, mask.limbs) |source_limb, mask_limb| {
1814+
for (source.limbs[0..len], mask.limbs[0..len]) |source_limb, mask_limb| {
18051815
const pext_limb = @extractBits(source_limb, mask_limb);
18061816
const shift_bits: Log2Limb = @intCast(shift % limb_bits);
18071817
const shift_limbs = shift / limb_bits;

lib/std/math/big/int_test.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2968,6 +2968,9 @@ test "big int extractBits" {
29682968

29692969
try extractBitsTest(0x12345678_90123456_78901234_56789012, 0xff << 64, 0x56);
29702970
try extractBitsTest(0x12345678_90123456_78901234_56789012, (0xff << 64) | 0xff00f, 0x56892);
2971+
2972+
try extractBitsTest(0x12345678_90123456_78901234_56789012, 0xf0f0, 0x91);
2973+
try extractBitsTest(0x12345678_90123456, 0xffffffff_ffffffff, 0x12345678_90123456);
29712974
}
29722975

29732976
fn extractBitsTest(comptime source: comptime_int, comptime mask: comptime_int, comptime expected: comptime_int) !void {
@@ -2992,6 +2995,8 @@ test "big int depositBits" {
29922995

29932996
try depositBitsTest(0x1234, 0xff << 64, 0x34_00000000_00000000);
29942997
try depositBitsTest(0x12345678, (0xff << 64) | 0xff00f, 0x45_00000000_00067008);
2998+
2999+
try depositBitsTest(0x0, 0xff_ffffffff_ffffffff, 0x0);
29953000
}
29963001

29973002
fn depositBitsTest(comptime source: comptime_int, comptime mask: comptime_int, comptime expected: comptime_int) !void {

0 commit comments

Comments
 (0)