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 {
489489 if (msl < req_limbs) {
490490 r.limbs[msl] = 1;
491491 r.len = req_limbs;
492 mem.set(Limb, r.limbs[msl + 1 .. req_limbs], 0);
492493 } else {
493494 carry_truncated = true;
494495 }
lib/std/math/big/int_test.zig+32-5
......@@ -1,4 +1,5 @@
11const std = @import("../../std.zig");
2const builtin = @import("builtin");
23const mem = std.mem;
34const testing = std.testing;
45const Managed = std.math.big.int.Managed;
......@@ -2123,6 +2124,33 @@ test "big.int bitNotWrap signed multi" {
21232124 try testing.expect((try a.to(SignedDoubleLimb)) == -1);
21242125}
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
21262154test "big.int bitwise and simple" {
21272155 var a = try Managed.initSet(testing.allocator, 0xffffffff11111111);
21282156 defer a.deinit();
......@@ -2655,11 +2683,10 @@ test "big int popcount" {
26552683 try popCountTest(&a, limb_size * 2 - 1, limb_size);
26562684 try popCountTest(&a, limb_size * 2, limb_size + 1);
26572685 try popCountTest(&a, limb_size * 2 + 1, limb_size + 2);
2658 // TODO: These produce incorrect pop count for Mutable
2659 // https://github.com/ziglang/zig/issues/13571
2660 // try popCountTest(&a, limb_size * 2 + 2, limb_size + 3);
2661 // try popCountTest(&a, limb_size * 2 + 3, limb_size + 4);
2662 // try popCountTest(&a, limb_size * 2 + 4, limb_size + 5);
2686 try popCountTest(&a, limb_size * 2 + 2, limb_size + 3);
2687 try popCountTest(&a, limb_size * 2 + 3, limb_size + 4);
2688 try popCountTest(&a, limb_size * 2 + 4, limb_size + 5);
2689 try popCountTest(&a, limb_size * 4 + 2, limb_size * 3 + 3);
26632690}
26642691
26652692fn popCountTest(val: *const Managed, bit_count: usize, expected: usize) !void {