authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-04 22:12:32-04:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-05 08:23:07+02:00
logad5fb4879b03267f196004a78762de7be3b03de7
tree41e45bbe941ad1fd1f904df2bb7fcad9ad772d73
parenta503724801e7b221aababd88aefe790a33c4135e

std: fix memory bugs

This fixes logged errors during CI based on the new GPA checks.

2 files changed, 30 insertions(+), 31 deletions(-)

lib/std/fs/path.zig+7-9
...@@ -1088,21 +1088,19 @@ pub fn relativeWindows(allocator: Allocator, from: []const u8, to: []const u8) !...@@ -1088,21 +1088,19 @@ pub fn relativeWindows(allocator: Allocator, from: []const u8, to: []const u8) !
1088 if (ascii.eqlIgnoreCase(from_component, to_component))1088 if (ascii.eqlIgnoreCase(from_component, to_component))
1089 continue;1089 continue;
1090 }1090 }
1091 var up_count: usize = 1;1091 var up_index_end = "..".len;
1092 while (from_it.next()) |_| {1092 while (from_it.next()) |_| {
1093 up_count += 1;1093 up_index_end += "\\..".len;
1094 }1094 }
1095 const up_index_end = up_count * "..\\".len;1095 const result = try allocator.alloc(u8, up_index_end + @boolToInt(to_rest.len > 0) + to_rest.len);
1096 const result = try allocator.alloc(u8, up_index_end + to_rest.len);
1097 errdefer allocator.free(result);1096 errdefer allocator.free(result);
10981097
1099 var result_index: usize = 0;1098 result[0..2].* = "..".*;
1099 var result_index: usize = 2;
1100 while (result_index < up_index_end) {1100 while (result_index < up_index_end) {
1101 result[result_index..][0..3].* = "..\\".*;1101 result[result_index..][0..3].* = "\\..".*;
1102 result_index += 3;1102 result_index += 3;
1103 }1103 }
1104 // shave off the trailing slash
1105 result_index -= 1;
11061104
1107 var rest_it = mem.tokenize(u8, to_rest, "/\\");1105 var rest_it = mem.tokenize(u8, to_rest, "/\\");
1108 while (rest_it.next()) |to_component| {1106 while (rest_it.next()) |to_component| {
...@@ -1112,7 +1110,7 @@ pub fn relativeWindows(allocator: Allocator, from: []const u8, to: []const u8) !...@@ -1112,7 +1110,7 @@ pub fn relativeWindows(allocator: Allocator, from: []const u8, to: []const u8) !
1112 result_index += to_component.len;1110 result_index += to_component.len;
1113 }1111 }
11141112
1115 return result[0..result_index];1113 return allocator.realloc(result, result_index);
1116 }1114 }
11171115
1118 return [_]u8{};1116 return [_]u8{};
lib/std/heap/arena_allocator.zig+23-22
...@@ -12,7 +12,7 @@ pub const ArenaAllocator = struct {...@@ -12,7 +12,7 @@ pub const ArenaAllocator = struct {
12 /// Inner state of ArenaAllocator. Can be stored rather than the entire ArenaAllocator12 /// Inner state of ArenaAllocator. Can be stored rather than the entire ArenaAllocator
13 /// as a memory-saving optimization.13 /// as a memory-saving optimization.
14 pub const State = struct {14 pub const State = struct {
15 buffer_list: std.SinglyLinkedList([]u8) = @as(std.SinglyLinkedList([]u8), .{}),15 buffer_list: std.SinglyLinkedList(usize) = .{},
16 end_index: usize = 0,16 end_index: usize = 0,
1717
18 pub fn promote(self: State, child_allocator: Allocator) ArenaAllocator {18 pub fn promote(self: State, child_allocator: Allocator) ArenaAllocator {
...@@ -34,7 +34,7 @@ pub const ArenaAllocator = struct {...@@ -34,7 +34,7 @@ pub const ArenaAllocator = struct {
34 };34 };
35 }35 }
3636
37 const BufNode = std.SinglyLinkedList([]u8).Node;37 const BufNode = std.SinglyLinkedList(usize).Node;
3838
39 pub fn init(child_allocator: Allocator) ArenaAllocator {39 pub fn init(child_allocator: Allocator) ArenaAllocator {
40 return (State{}).promote(child_allocator);40 return (State{}).promote(child_allocator);
...@@ -47,7 +47,9 @@ pub const ArenaAllocator = struct {...@@ -47,7 +47,9 @@ pub const ArenaAllocator = struct {
47 while (it) |node| {47 while (it) |node| {
48 // this has to occur before the free because the free frees node48 // this has to occur before the free because the free frees node
49 const next_it = node.next;49 const next_it = node.next;
50 self.child_allocator.free(node.data);50 const align_bits = std.math.log2_int(usize, @alignOf(BufNode));
51 const alloc_buf = @ptrCast([*]u8, node)[0..node.data];
52 self.child_allocator.rawFree(alloc_buf, align_bits, @returnAddress());
51 it = next_it;53 it = next_it;
52 }54 }
53 }55 }
...@@ -73,7 +75,7 @@ pub const ArenaAllocator = struct {...@@ -73,7 +75,7 @@ pub const ArenaAllocator = struct {
73 while (it) |node| : (it = node.next) {75 while (it) |node| : (it = node.next) {
74 // Compute the actually allocated size excluding the76 // Compute the actually allocated size excluding the
75 // linked list node.77 // linked list node.
76 size += node.data.len - @sizeOf(BufNode);78 size += node.data - @sizeOf(BufNode);
77 }79 }
78 return size;80 return size;
79 }81 }
...@@ -121,6 +123,7 @@ pub const ArenaAllocator = struct {...@@ -121,6 +123,7 @@ pub const ArenaAllocator = struct {
121 .retain_with_limit => |limit| std.math.min(limit, current_capacity),123 .retain_with_limit => |limit| std.math.min(limit, current_capacity),
122 .free_all => unreachable,124 .free_all => unreachable,
123 };125 };
126 const align_bits = std.math.log2_int(usize, @alignOf(BufNode));
124 // Free all nodes except for the last one127 // Free all nodes except for the last one
125 var it = self.state.buffer_list.first;128 var it = self.state.buffer_list.first;
126 const maybe_first_node = while (it) |node| {129 const maybe_first_node = while (it) |node| {
...@@ -128,7 +131,8 @@ pub const ArenaAllocator = struct {...@@ -128,7 +131,8 @@ pub const ArenaAllocator = struct {
128 const next_it = node.next;131 const next_it = node.next;
129 if (next_it == null)132 if (next_it == null)
130 break node;133 break node;
131 self.child_allocator.free(node.data);134 const alloc_buf = @ptrCast([*]u8, node)[0..node.data];
135 self.child_allocator.rawFree(alloc_buf, align_bits, @returnAddress());
132 it = next_it;136 it = next_it;
133 } else null;137 } else null;
134 std.debug.assert(maybe_first_node == null or maybe_first_node.?.next == null);138 std.debug.assert(maybe_first_node == null or maybe_first_node.?.next == null);
...@@ -136,23 +140,21 @@ pub const ArenaAllocator = struct {...@@ -136,23 +140,21 @@ pub const ArenaAllocator = struct {
136 self.state.end_index = 0;140 self.state.end_index = 0;
137 if (maybe_first_node) |first_node| {141 if (maybe_first_node) |first_node| {
138 // perfect, no need to invoke the child_allocator142 // perfect, no need to invoke the child_allocator
139 if (first_node.data.len == total_size)143 if (first_node.data == total_size)
140 return true;144 return true;
141 const align_bits = std.math.log2_int(usize, @alignOf(BufNode));145 const first_alloc_buf = @ptrCast([*]u8, first_node)[0..first_node.data];
142 if (self.child_allocator.rawResize(first_node.data, align_bits, total_size, @returnAddress())) {146 if (self.child_allocator.rawResize(first_alloc_buf, align_bits, total_size, @returnAddress())) {
143 // successful resize147 // successful resize
144 first_node.data.len = total_size;148 first_node.data = total_size;
145 } else {149 } else {
146 // manual realloc150 // manual realloc
147 const new_ptr = self.child_allocator.rawAlloc(total_size, align_bits, @returnAddress()) orelse {151 const new_ptr = self.child_allocator.rawAlloc(total_size, align_bits, @returnAddress()) orelse {
148 // we failed to preheat the arena properly, signal this to the user.152 // we failed to preheat the arena properly, signal this to the user.
149 return false;153 return false;
150 };154 };
151 self.child_allocator.rawFree(first_node.data, align_bits, @returnAddress());155 self.child_allocator.rawFree(first_alloc_buf, align_bits, @returnAddress());
152 const node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), new_ptr));156 const node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), new_ptr));
153 node.* = BufNode{157 node.* = .{ .data = total_size };
154 .data = new_ptr[0..total_size],
155 };
156 self.state.buffer_list.first = node;158 self.state.buffer_list.first = node;
157 }159 }
158 }160 }
...@@ -167,10 +169,7 @@ pub const ArenaAllocator = struct {...@@ -167,10 +169,7 @@ pub const ArenaAllocator = struct {
167 const ptr = self.child_allocator.rawAlloc(len, log2_align, @returnAddress()) orelse169 const ptr = self.child_allocator.rawAlloc(len, log2_align, @returnAddress()) orelse
168 return null;170 return null;
169 const buf_node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), ptr));171 const buf_node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), ptr));
170 buf_node.* = BufNode{172 buf_node.* = .{ .data = len };
171 .data = ptr[0..len],
172 .next = null,
173 };
174 self.state.buffer_list.prepend(buf_node);173 self.state.buffer_list.prepend(buf_node);
175 self.state.end_index = 0;174 self.state.end_index = 0;
176 return buf_node;175 return buf_node;
...@@ -186,7 +185,8 @@ pub const ArenaAllocator = struct {...@@ -186,7 +185,8 @@ pub const ArenaAllocator = struct {
186 else185 else
187 (self.createNode(0, n + ptr_align) orelse return null);186 (self.createNode(0, n + ptr_align) orelse return null);
188 while (true) {187 while (true) {
189 const cur_buf = cur_node.data[@sizeOf(BufNode)..];188 const cur_alloc_buf = @ptrCast([*]u8, cur_node)[0..cur_node.data];
189 const cur_buf = cur_alloc_buf[@sizeOf(BufNode)..];
190 const addr = @ptrToInt(cur_buf.ptr) + self.state.end_index;190 const addr = @ptrToInt(cur_buf.ptr) + self.state.end_index;
191 const adjusted_addr = mem.alignForward(addr, ptr_align);191 const adjusted_addr = mem.alignForward(addr, ptr_align);
192 const adjusted_index = self.state.end_index + (adjusted_addr - addr);192 const adjusted_index = self.state.end_index + (adjusted_addr - addr);
...@@ -199,8 +199,9 @@ pub const ArenaAllocator = struct {...@@ -199,8 +199,9 @@ pub const ArenaAllocator = struct {
199 }199 }
200200
201 const bigger_buf_size = @sizeOf(BufNode) + new_end_index;201 const bigger_buf_size = @sizeOf(BufNode) + new_end_index;
202 if (self.child_allocator.resize(cur_node.data, bigger_buf_size)) {202 const log2_align = comptime std.math.log2_int(usize, @alignOf(BufNode));
203 cur_node.data.len = bigger_buf_size;203 if (self.child_allocator.rawResize(cur_alloc_buf, log2_align, bigger_buf_size, @returnAddress())) {
204 cur_node.data = bigger_buf_size;
204 } else {205 } else {
205 // Allocate a new node if that's not possible206 // Allocate a new node if that's not possible
206 cur_node = self.createNode(cur_buf.len, n + ptr_align) orelse return null;207 cur_node = self.createNode(cur_buf.len, n + ptr_align) orelse return null;
...@@ -214,7 +215,7 @@ pub const ArenaAllocator = struct {...@@ -214,7 +215,7 @@ pub const ArenaAllocator = struct {
214 _ = ret_addr;215 _ = ret_addr;
215216
216 const cur_node = self.state.buffer_list.first orelse return false;217 const cur_node = self.state.buffer_list.first orelse return false;
217 const cur_buf = cur_node.data[@sizeOf(BufNode)..];218 const cur_buf = @ptrCast([*]u8, cur_node)[@sizeOf(BufNode)..cur_node.data];
218 if (@ptrToInt(cur_buf.ptr) + self.state.end_index != @ptrToInt(buf.ptr) + buf.len) {219 if (@ptrToInt(cur_buf.ptr) + self.state.end_index != @ptrToInt(buf.ptr) + buf.len) {
219 // It's not the most recent allocation, so it cannot be expanded,220 // It's not the most recent allocation, so it cannot be expanded,
220 // but it's fine if they want to make it smaller.221 // but it's fine if they want to make it smaller.
...@@ -239,7 +240,7 @@ pub const ArenaAllocator = struct {...@@ -239,7 +240,7 @@ pub const ArenaAllocator = struct {
239 const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx));240 const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx));
240241
241 const cur_node = self.state.buffer_list.first orelse return;242 const cur_node = self.state.buffer_list.first orelse return;
242 const cur_buf = cur_node.data[@sizeOf(BufNode)..];243 const cur_buf = @ptrCast([*]u8, cur_node)[@sizeOf(BufNode)..cur_node.data];
243244
244 if (@ptrToInt(cur_buf.ptr) + self.state.end_index == @ptrToInt(buf.ptr) + buf.len) {245 if (@ptrToInt(cur_buf.ptr) + self.state.end_index == @ptrToInt(buf.ptr) + buf.len) {
245 self.state.end_index -= buf.len;246 self.state.end_index -= buf.len;