authorgravatar for codroid@gmail.comStevie Hryciw <codroid@gmail.com> 2023-01-27 18:16:22-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-20 16:00:37-07:00
loge8fdb249b673e3d69225c1b7cba68bdfc63061b1
tree64cc5767e20006ef393ca2f1b3602f9be3f98eee
parent7d90410b96f4b2393133e184f72b2846d3ff5ac7

std.math.big.int: Initialize limbs in addWrap

When a big.Int.Mutable had more than two limbs, it was possible for this function to change the `len` field without zeroing limbs in the active range. These uninitialized limbs would then be used in `truncate()` and could cause invalid results. Closes #13571

2 files changed, 33 insertions(+), 5 deletions(-)

lib/std/math/big/int.zig+1
...@@ -489,6 +489,7 @@ pub const Mutable = struct {...@@ -489,6 +489,7 @@ pub const Mutable = struct {
489 if (msl < req_limbs) {489 if (msl < req_limbs) {
490 r.limbs[msl] = 1;490 r.limbs[msl] = 1;
491 r.len = req_limbs;491 r.len = req_limbs;
492 mem.set(Limb, r.limbs[msl + 1 .. req_limbs], 0);
492 } else {493 } else {
493 carry_truncated = true;494 carry_truncated = true;
494 }495 }
lib/std/math/big/int_test.zig+32-5
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("../../std.zig");1const std = @import("../../std.zig");
2const builtin = @import("builtin");
2const mem = std.mem;3const mem = std.mem;
3const testing = std.testing;4const testing = std.testing;
4const Managed = std.math.big.int.Managed;5const Managed = std.math.big.int.Managed;
...@@ -2123,6 +2124,33 @@ test "big.int bitNotWrap signed multi" {...@@ -2123,6 +2124,33 @@ test "big.int bitNotWrap signed multi" {
2123 try testing.expect((try a.to(SignedDoubleLimb)) == -1);2124 try testing.expect((try a.to(SignedDoubleLimb)) == -1);
2124}2125}
21252126
2127test "big.int bitNotWrap more than two limbs" {
2128 // This test requires int sizes greater than 128 bits.
2129 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2130 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
2131 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2134 // LLVM: unexpected runtime library name: __umodei4
2135 if (builtin.zig_backend == .stage2_llvm and comptime builtin.target.isWasm()) return error.SkipZigTest; // TODO
2136
2137 var a = try Managed.initSet(testing.allocator, maxInt(Limb));
2138 defer a.deinit();
2139
2140 var res = try Managed.init(testing.allocator);
2141 defer res.deinit();
2142
2143 const bits = @bitSizeOf(Limb) * 4 + 2;
2144
2145 try res.bitNotWrap(&a, .unsigned, bits);
2146 const Unsigned = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = bits } });
2147 try testing.expectEqual((try res.to(Unsigned)), ~@as(Unsigned, maxInt(Limb)));
2148
2149 try res.bitNotWrap(&a, .signed, bits);
2150 const Signed = @Type(.{ .Int = .{ .signedness = .signed, .bits = bits } });
2151 try testing.expectEqual((try res.to(Signed)), ~@as(Signed, maxInt(Limb)));
2152}
2153
2126test "big.int bitwise and simple" {2154test "big.int bitwise and simple" {
2127 var a = try Managed.initSet(testing.allocator, 0xffffffff11111111);2155 var a = try Managed.initSet(testing.allocator, 0xffffffff11111111);
2128 defer a.deinit();2156 defer a.deinit();
...@@ -2655,11 +2683,10 @@ test "big int popcount" {...@@ -2655,11 +2683,10 @@ test "big int popcount" {
2655 try popCountTest(&a, limb_size * 2 - 1, limb_size);2683 try popCountTest(&a, limb_size * 2 - 1, limb_size);
2656 try popCountTest(&a, limb_size * 2, limb_size + 1);2684 try popCountTest(&a, limb_size * 2, limb_size + 1);
2657 try popCountTest(&a, limb_size * 2 + 1, limb_size + 2);2685 try popCountTest(&a, limb_size * 2 + 1, limb_size + 2);
2658 // TODO: These produce incorrect pop count for Mutable2686 try popCountTest(&a, limb_size * 2 + 2, limb_size + 3);
2659 // https://github.com/ziglang/zig/issues/135712687 try popCountTest(&a, limb_size * 2 + 3, limb_size + 4);
2660 // try popCountTest(&a, limb_size * 2 + 2, limb_size + 3);2688 try popCountTest(&a, limb_size * 2 + 4, limb_size + 5);
2661 // try popCountTest(&a, limb_size * 2 + 3, limb_size + 4);2689 try popCountTest(&a, limb_size * 4 + 2, limb_size * 3 + 3);
2662 // try popCountTest(&a, limb_size * 2 + 4, limb_size + 5);
2663}2690}
26642691
2665fn popCountTest(val: *const Managed, bit_count: usize, expected: usize) !void {2692fn popCountTest(val: *const Managed, bit_count: usize, expected: usize) !void {