authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-19 12:10:00-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-01-19 12:10:00-08:00
log3c16e8037261e2f19e4a4daf9c88453ec11281b3
tree2347f6305f921c3c87f30b343a9cae3b4d5c505e
parent100efcf8d3e7fb7562d51b011dfaf639bf93c9ba
parentc50ba2d1019b025d278e0644903b1358a70415b5
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #18611 from erikarvstedt/array-list-overflow

ArrayList: remove unneeded overflow checks

1 files changed, 35 insertions(+), 37 deletions(-)

lib/std/array_list.zig+35-37
...@@ -126,7 +126,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -126,7 +126,8 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
126126
127 /// The caller owns the returned memory. Empties this ArrayList.127 /// The caller owns the returned memory. Empties this ArrayList.
128 pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {128 pub fn toOwnedSliceSentinel(self: *Self, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {
129 try self.ensureTotalCapacityPrecise(try addOrOom(self.items.len, 1));129 // This addition can never overflow because `self.items` can never occupy the whole address space
130 try self.ensureTotalCapacityPrecise(self.items.len + 1);
130 self.appendAssumeCapacity(sentinel);131 self.appendAssumeCapacity(sentinel);
131 const result = try self.toOwnedSlice();132 const result = try self.toOwnedSlice();
132 return result[0 .. result.len - 1 :sentinel];133 return result[0 .. result.len - 1 :sentinel];
...@@ -241,9 +242,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -241,9 +242,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
241 /// Grows list if `len < new_items.len`.242 /// Grows list if `len < new_items.len`.
242 /// Shrinks list if `len > new_items.len`.243 /// Shrinks list if `len > new_items.len`.
243 /// Invalidates element pointers if this ArrayList is resized.244 /// Invalidates element pointers if this ArrayList is resized.
244 /// Asserts that the start index is in bounds or equal to the length.245 /// Asserts that the range is in bounds.
245 pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void {246 pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: []const T) Allocator.Error!void {
246 const after_range = try addOrOom(start, len);247 const after_range = start + len;
247 const range = self.items[start..after_range];248 const range = self.items[start..after_range];
248249
249 if (range.len == new_items.len)250 if (range.len == new_items.len)
...@@ -256,7 +257,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -256,7 +257,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
256 try self.insertSlice(after_range, rest);257 try self.insertSlice(after_range, rest);
257 } else {258 } else {
258 @memcpy(range[0..new_items.len], new_items);259 @memcpy(range[0..new_items.len], new_items);
259 const after_subrange = try addOrOom(start, new_items.len);260 const after_subrange = start + new_items.len;
260261
261 for (self.items[after_range..], 0..) |item, i| {262 for (self.items[after_range..], 0..) |item, i| {
262 self.items[after_subrange..][i] = item;263 self.items[after_subrange..][i] = item;
...@@ -493,7 +494,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -493,7 +494,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
493 /// Increase length by 1, returning pointer to the new item.494 /// Increase length by 1, returning pointer to the new item.
494 /// The returned pointer becomes invalid when the list resized.495 /// The returned pointer becomes invalid when the list resized.
495 pub fn addOne(self: *Self) Allocator.Error!*T {496 pub fn addOne(self: *Self) Allocator.Error!*T {
496 try self.ensureUnusedCapacity(1);497 // This can never overflow because `self.items` can never occupy the whole address space
498 const newlen = self.items.len + 1;
499 try self.ensureTotalCapacity(newlen);
497 return self.addOneAssumeCapacity();500 return self.addOneAssumeCapacity();
498 }501 }
499502
...@@ -710,7 +713,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -710,7 +713,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
710713
711 /// The caller owns the returned memory. ArrayList becomes empty.714 /// The caller owns the returned memory. ArrayList becomes empty.
712 pub fn toOwnedSliceSentinel(self: *Self, allocator: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {715 pub fn toOwnedSliceSentinel(self: *Self, allocator: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {
713 try self.ensureTotalCapacityPrecise(allocator, try addOrOom(self.items.len, 1));716 // This addition can never overflow because `self.items` can never occupy the whole address space
717 try self.ensureTotalCapacityPrecise(allocator, self.items.len + 1);
714 self.appendAssumeCapacity(sentinel);718 self.appendAssumeCapacity(sentinel);
715 const result = try self.toOwnedSlice(allocator);719 const result = try self.toOwnedSlice(allocator);
716 return result[0 .. result.len - 1 :sentinel];720 return result[0 .. result.len - 1 :sentinel];
...@@ -1071,7 +1075,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -1071,7 +1075,8 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
1071 /// Increase length by 1, returning pointer to the new item.1075 /// Increase length by 1, returning pointer to the new item.
1072 /// The returned element pointer becomes invalid when the list is resized.1076 /// The returned element pointer becomes invalid when the list is resized.
1073 pub fn addOne(self: *Self, allocator: Allocator) Allocator.Error!*T {1077 pub fn addOne(self: *Self, allocator: Allocator) Allocator.Error!*T {
1074 const newlen = try addOrOom(self.items.len, 1);1078 // This can never overflow because `self.items` can never occupy the whole address space
1079 const newlen = self.items.len + 1;
1075 try self.ensureTotalCapacity(allocator, newlen);1080 try self.ensureTotalCapacity(allocator, newlen);
1076 return self.addOneAssumeCapacity();1081 return self.addOneAssumeCapacity();
1077 }1082 }
...@@ -1991,47 +1996,40 @@ test "std.ArrayList(u32).getLastOrNull()" {...@@ -1991,47 +1996,40 @@ test "std.ArrayList(u32).getLastOrNull()" {
1991test "return OutOfMemory when capacity would exceed maximum usize integer value" {1996test "return OutOfMemory when capacity would exceed maximum usize integer value" {
1992 const a = testing.allocator;1997 const a = testing.allocator;
1993 const new_item: u32 = 42;1998 const new_item: u32 = 42;
1999 const items = &.{ 42, 43 };
19942000
1995 {2001 {
1996 var list: ArrayListUnmanaged(u32) = .{2002 var list: ArrayListUnmanaged(u32) = .{
1997 .items = undefined,2003 .items = undefined,
1998 .capacity = math.maxInt(usize),2004 .capacity = math.maxInt(usize) - 1,
1999 };2005 };
2000 list.items.len = math.maxInt(usize);2006 list.items.len = math.maxInt(usize) - 1;
20012007
2002 try testing.expectError(error.OutOfMemory, list.append(a, new_item));2008 try testing.expectError(error.OutOfMemory, list.appendSlice(a, items));
2003 try testing.expectError(error.OutOfMemory, list.appendSlice(a, &.{new_item}));2009 try testing.expectError(error.OutOfMemory, list.appendNTimes(a, new_item, 2));
2004 try testing.expectError(error.OutOfMemory, list.appendNTimes(a, new_item, 1));2010 try testing.expectError(error.OutOfMemory, list.appendUnalignedSlice(a, &.{ new_item, new_item }));
2005 try testing.expectError(error.OutOfMemory, list.appendUnalignedSlice(a, &.{new_item}));2011 try testing.expectError(error.OutOfMemory, list.addManyAt(a, 0, 2));
2006 try testing.expectError(error.OutOfMemory, list.addOne(a));2012 try testing.expectError(error.OutOfMemory, list.addManyAsArray(a, 2));
2007 try testing.expectError(error.OutOfMemory, list.addManyAt(a, 0, 1));2013 try testing.expectError(error.OutOfMemory, list.addManyAsSlice(a, 2));
2008 try testing.expectError(error.OutOfMemory, list.addManyAsArray(a, 1));2014 try testing.expectError(error.OutOfMemory, list.insertSlice(a, 0, items));
2009 try testing.expectError(error.OutOfMemory, list.addManyAsSlice(a, 1));2015 try testing.expectError(error.OutOfMemory, list.ensureUnusedCapacity(a, 2));
2010 try testing.expectError(error.OutOfMemory, list.insert(a, 0, new_item));
2011 try testing.expectError(error.OutOfMemory, list.insertSlice(a, 0, &.{new_item}));
2012 try testing.expectError(error.OutOfMemory, list.toOwnedSliceSentinel(a, 0));
2013 try testing.expectError(error.OutOfMemory, list.ensureUnusedCapacity(a, 1));
2014 }2016 }
20152017
2016 {2018 {
2017 var list: ArrayList(u32) = .{2019 var list: ArrayList(u32) = .{
2018 .items = undefined,2020 .items = undefined,
2019 .capacity = math.maxInt(usize),2021 .capacity = math.maxInt(usize) - 1,
2020 .allocator = a,2022 .allocator = a,
2021 };2023 };
2022 list.items.len = math.maxInt(usize);2024 list.items.len = math.maxInt(usize) - 1;
20232025
2024 try testing.expectError(error.OutOfMemory, list.append(new_item));2026 try testing.expectError(error.OutOfMemory, list.appendSlice(items));
2025 try testing.expectError(error.OutOfMemory, list.appendSlice(&.{new_item}));2027 try testing.expectError(error.OutOfMemory, list.appendNTimes(new_item, 2));
2026 try testing.expectError(error.OutOfMemory, list.appendNTimes(new_item, 1));2028 try testing.expectError(error.OutOfMemory, list.appendUnalignedSlice(&.{ new_item, new_item }));
2027 try testing.expectError(error.OutOfMemory, list.appendUnalignedSlice(&.{new_item}));2029 try testing.expectError(error.OutOfMemory, list.addManyAt(0, 2));
2028 try testing.expectError(error.OutOfMemory, list.addOne());2030 try testing.expectError(error.OutOfMemory, list.addManyAsArray(2));
2029 try testing.expectError(error.OutOfMemory, list.addManyAt(0, 1));2031 try testing.expectError(error.OutOfMemory, list.addManyAsSlice(2));
2030 try testing.expectError(error.OutOfMemory, list.addManyAsArray(1));2032 try testing.expectError(error.OutOfMemory, list.insertSlice(0, items));
2031 try testing.expectError(error.OutOfMemory, list.addManyAsSlice(1));2033 try testing.expectError(error.OutOfMemory, list.ensureUnusedCapacity(2));
2032 try testing.expectError(error.OutOfMemory, list.insert(0, new_item));
2033 try testing.expectError(error.OutOfMemory, list.insertSlice(0, &.{new_item}));
2034 try testing.expectError(error.OutOfMemory, list.toOwnedSliceSentinel(0));
2035 try testing.expectError(error.OutOfMemory, list.ensureUnusedCapacity(1));
2036 }2034 }
2037}2035}