authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-03-12 22:04:41-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-03-23 21:59:12-04:00
log7757302c3aa230a30770b4ff7a9b033e621c0178
tree5305b083e0a4d6dbf5e9d936c9f65a53d2f1689e
parent4f47be5c6bbf67ed6812978759307d5d6de041ba

big.int: fix negative multi-limb shift right adjust crash


2 files changed, 13 insertions(+), 10 deletions(-)

lib/std/math/big/int.zig+4-10
...@@ -1096,7 +1096,7 @@ pub const Mutable = struct {...@@ -1096,7 +1096,7 @@ pub const Mutable = struct {
1096 /// Asserts there is enough memory to fit the result. The upper bound Limb count is1096 /// Asserts there is enough memory to fit the result. The upper bound Limb count is
1097 /// `a.limbs.len + (shift / (@sizeOf(Limb) * 8))`.1097 /// `a.limbs.len + (shift / (@sizeOf(Limb) * 8))`.
1098 pub fn shiftLeft(r: *Mutable, a: Const, shift: usize) void {1098 pub fn shiftLeft(r: *Mutable, a: Const, shift: usize) void {
1099 llshl(r.limbs[0..], a.limbs[0..a.limbs.len], shift);1099 llshl(r.limbs, a.limbs, shift);
1100 r.normalize(a.limbs.len + (shift / limb_bits) + 1);1100 r.normalize(a.limbs.len + (shift / limb_bits) + 1);
1101 r.positive = a.positive;1101 r.positive = a.positive;
1102 }1102 }
...@@ -1165,7 +1165,7 @@ pub const Mutable = struct {...@@ -1165,7 +1165,7 @@ pub const Mutable = struct {
11651165
1166 // This shift should not be able to overflow, so invoke llshl and normalize manually1166 // This shift should not be able to overflow, so invoke llshl and normalize manually
1167 // to avoid the extra required limb.1167 // to avoid the extra required limb.
1168 llshl(r.limbs[0..], a.limbs[0..a.limbs.len], shift);1168 llshl(r.limbs, a.limbs, shift);
1169 r.normalize(a.limbs.len + (shift / limb_bits));1169 r.normalize(a.limbs.len + (shift / limb_bits));
1170 r.positive = a.positive;1170 r.positive = a.positive;
1171 }1171 }
...@@ -1202,17 +1202,11 @@ pub const Mutable = struct {...@@ -1202,17 +1202,11 @@ pub const Mutable = struct {
1202 break :nonzero a.limbs[full_limbs_shifted_out] << not_covered != 0;1202 break :nonzero a.limbs[full_limbs_shifted_out] << not_covered != 0;
1203 };1203 };
12041204
1205 llshr(r.limbs[0..], a.limbs[0..a.limbs.len], shift);1205 llshr(r.limbs, a.limbs, shift);
12061206
1207 r.len = a.limbs.len - full_limbs_shifted_out;1207 r.len = a.limbs.len - full_limbs_shifted_out;
1208 r.positive = a.positive;1208 r.positive = a.positive;
1209 if (nonzero_negative_shiftout) {1209 if (nonzero_negative_shiftout) r.addScalar(r.toConst(), -1);
1210 if (full_limbs_shifted_out > 0) {
1211 r.limbs[a.limbs.len - full_limbs_shifted_out] = 0;
1212 r.len += 1;
1213 }
1214 r.addScalar(r.toConst(), -1);
1215 }
1216 r.normalize(r.len);1210 r.normalize(r.len);
1217 }1211 }
12181212
lib/std/math/big/int_test.zig+9
...@@ -2191,6 +2191,15 @@ test "shift-right negative" {...@@ -2191,6 +2191,15 @@ test "shift-right negative" {
2191 a.setSign(true);2191 a.setSign(true);
2192 try a.shiftRight(&arg7, 4);2192 try a.shiftRight(&arg7, 4);
2193 try testing.expect(try a.toInt(i16) == -2048);2193 try testing.expect(try a.toInt(i16) == -2048);
2194
2195 var arg8_limbs: [1]Limb = undefined;
2196 var arg8: Mutable = .{
2197 .limbs = &arg8_limbs,
2198 .len = undefined,
2199 .positive = undefined,
2200 };
2201 arg8.shiftRight(.{ .limbs = &.{ 1, 1 }, .positive = false }, @bitSizeOf(Limb));
2202 try testing.expect(arg8.toConst().orderAgainstScalar(-2).compare(.eq));
2194}2203}
21952204
2196test "sat shift-left simple unsigned" {2205test "sat shift-left simple unsigned" {