authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-25 19:49:40-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-25 19:49:40-07:00
logb498eebfd450e7579dc8652d5827a23cc7070d9d
treede5346194d4667905303d35509ec2d6a9f721f8b
parent973e6c978cedacc9aab86999ab67e5066fc1db1d

std.math.big: fix use-after-free

When there is parameter aliasing, the ensureCapacity calls can cause the Const parameters to become dangling pointers. See #6167

2 files changed, 26 insertions(+), 18 deletions(-)

lib/std/math/big/int.zig+25-18
......@@ -15,6 +15,8 @@ const maxInt = std.math.maxInt;
1515const minInt = std.math.minInt;
1616const assert = std.debug.assert;
1717
18const debug_safety = false;
19
1820/// Returns the number of limbs needed to store `scalar`, which must be a
1921/// primitive integer value.
2022pub fn calcLimbLen(scalar: anytype) usize {
......@@ -57,7 +59,7 @@ pub fn calcSetStringLimbCount(base: u8, string_len: usize) usize {
5759
5860/// a + b * c + *carry, sets carry to the overflow bits
5961pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
60 @setRuntimeSafety(false);
62 @setRuntimeSafety(debug_safety);
6163 var r1: Limb = undefined;
6264
6365 // r1 = a + *carry
......@@ -1529,8 +1531,7 @@ pub const Managed = struct {
15291531 /// self's allocator is used for temporary storage to boost multiplication performance.
15301532 pub fn setString(self: *Managed, base: u8, value: []const u8) !void {
15311533 if (base < 2 or base > 16) return error.InvalidBase;
1532 const den = (@sizeOf(Limb) * 8 / base);
1533 try self.ensureCapacity((value.len + (den - 1)) / den);
1534 try self.ensureCapacity(calcSetStringLimbCount(base, value.len));
15341535 const limbs_buffer = try self.allocator.alloc(Limb, calcSetStringLimbsBufferLen(base, value.len));
15351536 defer self.allocator.free(limbs_buffer);
15361537 var m = self.toMutable();
......@@ -1646,17 +1647,19 @@ pub const Managed = struct {
16461647 /// rma = a * b
16471648 ///
16481649 /// rma, a and b may be aliases. However, it is more efficient if rma does not alias a or b.
1650 /// If rma aliases a or b, then caller must call `rma.ensureMulCapacity` prior to calling `mul`.
16491651 ///
16501652 /// Returns an error if memory could not be allocated.
16511653 ///
16521654 /// rma's allocator is used for temporary storage to speed up the multiplication.
16531655 pub fn mul(rma: *Managed, a: Const, b: Const) !void {
1654 try rma.ensureCapacity(a.limbs.len + b.limbs.len + 1);
16551656 var alias_count: usize = 0;
16561657 if (rma.limbs.ptr == a.limbs.ptr)
16571658 alias_count += 1;
16581659 if (rma.limbs.ptr == b.limbs.ptr)
16591660 alias_count += 1;
1661 assert(alias_count == 0 or rma.limbs.len >= a.limbs.len + b.limbs.len + 1);
1662 try rma.ensureMulCapacity(a, b);
16601663 var m = rma.toMutable();
16611664 if (alias_count == 0) {
16621665 m.mulNoAlias(a, b, rma.allocator);
......@@ -1669,6 +1672,10 @@ pub const Managed = struct {
16691672 rma.setMetadata(m.positive, m.len);
16701673 }
16711674
1675 pub fn ensureMulCapacity(rma: *Managed, a: Const, b: Const) !void {
1676 try rma.ensureCapacity(a.limbs.len + b.limbs.len + 1);
1677 }
1678
16721679 /// q = a / b (rem r)
16731680 ///
16741681 /// a / b are floored (rounded towards 0).
......@@ -1773,7 +1780,7 @@ pub const Managed = struct {
17731780///
17741781/// r MUST NOT alias any of a or b.
17751782fn llmulacc(opt_allocator: ?*Allocator, r: []Limb, a: []const Limb, b: []const Limb) void {
1776 @setRuntimeSafety(false);
1783 @setRuntimeSafety(debug_safety);
17771784
17781785 const a_norm = a[0..llnormalize(a)];
17791786 const b_norm = b[0..llnormalize(b)];
......@@ -1806,7 +1813,7 @@ fn llmulacc(opt_allocator: ?*Allocator, r: []Limb, a: []const Limb, b: []const L
18061813///
18071814/// r MUST NOT alias any of a or b.
18081815fn llmulacc_karatsuba(allocator: *Allocator, r: []Limb, x: []const Limb, y: []const Limb) error{OutOfMemory}!void {
1809 @setRuntimeSafety(false);
1816 @setRuntimeSafety(debug_safety);
18101817
18111818 assert(r.len >= x.len + y.len + 1);
18121819
......@@ -1873,7 +1880,7 @@ fn llmulacc_karatsuba(allocator: *Allocator, r: []Limb, x: []const Limb, y: []co
18731880
18741881// r = r + a
18751882fn llaccum(r: []Limb, a: []const Limb) Limb {
1876 @setRuntimeSafety(false);
1883 @setRuntimeSafety(debug_safety);
18771884 assert(r.len != 0 and a.len != 0);
18781885 assert(r.len >= a.len);
18791886
......@@ -1896,7 +1903,7 @@ fn llaccum(r: []Limb, a: []const Limb) Limb {
18961903
18971904/// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively for limbs.
18981905pub fn llcmp(a: []const Limb, b: []const Limb) i8 {
1899 @setRuntimeSafety(false);
1906 @setRuntimeSafety(debug_safety);
19001907 const a_len = llnormalize(a);
19011908 const b_len = llnormalize(b);
19021909 if (a_len < b_len) {
......@@ -1923,12 +1930,12 @@ pub fn llcmp(a: []const Limb, b: []const Limb) i8 {
19231930}
19241931
19251932fn llmulDigit(acc: []Limb, y: []const Limb, xi: Limb) void {
1926 @setRuntimeSafety(false);
1933 @setRuntimeSafety(debug_safety);
19271934 if (xi == 0) {
19281935 return;
19291936 }
19301937
1931 var carry: usize = 0;
1938 var carry: Limb = 0;
19321939 var a_lo = acc[0..y.len];
19331940 var a_hi = acc[y.len..];
19341941
......@@ -1945,7 +1952,7 @@ fn llmulDigit(acc: []Limb, y: []const Limb, xi: Limb) void {
19451952
19461953/// returns the min length the limb could be.
19471954fn llnormalize(a: []const Limb) usize {
1948 @setRuntimeSafety(false);
1955 @setRuntimeSafety(debug_safety);
19491956 var j = a.len;
19501957 while (j > 0) : (j -= 1) {
19511958 if (a[j - 1] != 0) {
......@@ -1959,7 +1966,7 @@ fn llnormalize(a: []const Limb) usize {
19591966
19601967/// Knuth 4.3.1, Algorithm S.
19611968fn llsub(r: []Limb, a: []const Limb, b: []const Limb) void {
1962 @setRuntimeSafety(false);
1969 @setRuntimeSafety(debug_safety);
19631970 assert(a.len != 0 and b.len != 0);
19641971 assert(a.len > b.len or (a.len == b.len and a[a.len - 1] >= b[b.len - 1]));
19651972 assert(r.len >= a.len);
......@@ -1983,7 +1990,7 @@ fn llsub(r: []Limb, a: []const Limb, b: []const Limb) void {
19831990
19841991/// Knuth 4.3.1, Algorithm A.
19851992fn lladd(r: []Limb, a: []const Limb, b: []const Limb) void {
1986 @setRuntimeSafety(false);
1993 @setRuntimeSafety(debug_safety);
19871994 assert(a.len != 0 and b.len != 0);
19881995 assert(a.len >= b.len);
19891996 assert(r.len >= a.len + 1);
......@@ -2007,7 +2014,7 @@ fn lladd(r: []Limb, a: []const Limb, b: []const Limb) void {
20072014
20082015/// Knuth 4.3.1, Exercise 16.
20092016fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void {
2010 @setRuntimeSafety(false);
2017 @setRuntimeSafety(debug_safety);
20112018 assert(a.len > 1 or a[0] >= b);
20122019 assert(quo.len >= a.len);
20132020
......@@ -2033,7 +2040,7 @@ fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void {
20332040}
20342041
20352042fn llshl(r: []Limb, a: []const Limb, shift: usize) void {
2036 @setRuntimeSafety(false);
2043 @setRuntimeSafety(debug_safety);
20372044 assert(a.len >= 1);
20382045 assert(r.len >= a.len + (shift / Limb.bit_count) + 1);
20392046
......@@ -2060,7 +2067,7 @@ fn llshl(r: []Limb, a: []const Limb, shift: usize) void {
20602067}
20612068
20622069fn llshr(r: []Limb, a: []const Limb, shift: usize) void {
2063 @setRuntimeSafety(false);
2070 @setRuntimeSafety(debug_safety);
20642071 assert(a.len >= 1);
20652072 assert(r.len >= a.len - (shift / Limb.bit_count));
20662073
......@@ -2084,7 +2091,7 @@ fn llshr(r: []Limb, a: []const Limb, shift: usize) void {
20842091}
20852092
20862093fn llor(r: []Limb, a: []const Limb, b: []const Limb) void {
2087 @setRuntimeSafety(false);
2094 @setRuntimeSafety(debug_safety);
20882095 assert(r.len >= a.len);
20892096 assert(a.len >= b.len);
20902097
......@@ -2098,7 +2105,7 @@ fn llor(r: []Limb, a: []const Limb, b: []const Limb) void {
20982105}
20992106
21002107fn lland(r: []Limb, a: []const Limb, b: []const Limb) void {
2101 @setRuntimeSafety(false);
2108 @setRuntimeSafety(debug_safety);
21022109 assert(r.len >= b.len);
21032110 assert(a.len >= b.len);
21042111
lib/std/math/big/rational.zig+1
......@@ -110,6 +110,7 @@ pub const Rational = struct {
110110
111111 var j: usize = start;
112112 while (j < str.len - i - 1) : (j += 1) {
113 try self.p.ensureMulCapacity(self.p.toConst(), base);
113114 try self.p.mul(self.p.toConst(), base);
114115 }
115116