authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-29 20:19:23-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-30 00:48:50-07:00
log9a0970a12bdcae105b6f3f65c0a72d95a209bd35
treeab0de8f2447b5e52c2bb5c92a976a52fb4b613ee
parent79f267f6b9e7f80a6fed3b1019f9de942841c3be

rework std.Io.Writer.Allocating to support runtime-known alignment

Also, breaking API changes to: * std.fs.Dir.readFileAlloc * std.fs.Dir.readFileAllocOptions

24 files changed, 280 insertions(+), 150 deletions(-)

lib/compiler/reduce.zig+2-3
...@@ -398,10 +398,9 @@ fn transformationsToFixups(...@@ -398,10 +398,9 @@ fn transformationsToFixups(
398398
399fn parse(gpa: Allocator, file_path: []const u8) !Ast {399fn parse(gpa: Allocator, file_path: []const u8) !Ast {
400 const source_code = std.fs.cwd().readFileAllocOptions(400 const source_code = std.fs.cwd().readFileAllocOptions(
401 gpa,
402 file_path,401 file_path,
403 std.math.maxInt(u32),402 gpa,
404 null,403 .limited(std.math.maxInt(u32)),
405 .fromByteUnits(1),404 .fromByteUnits(1),
406 0,405 0,
407 ) catch |err| {406 ) catch |err| {
lib/compiler/std-docs.zig+2-2
...@@ -173,7 +173,7 @@ fn serveDocsFile(...@@ -173,7 +173,7 @@ fn serveDocsFile(
173 // The desired API is actually sendfile, which will require enhancing std.http.Server.173 // The desired API is actually sendfile, which will require enhancing std.http.Server.
174 // We load the file with every request so that the user can make changes to the file174 // We load the file with every request so that the user can make changes to the file
175 // and refresh the HTML page without restarting this server.175 // and refresh the HTML page without restarting this server.
176 const file_contents = try context.lib_dir.readFileAlloc(gpa, name, 10 * 1024 * 1024);176 const file_contents = try context.lib_dir.readFileAlloc(name, gpa, .limited(10 * 1024 * 1024));
177 defer gpa.free(file_contents);177 defer gpa.free(file_contents);
178 try request.respond(file_contents, .{178 try request.respond(file_contents, .{
179 .extra_headers = &.{179 .extra_headers = &.{
...@@ -263,7 +263,7 @@ fn serveWasm(...@@ -263,7 +263,7 @@ fn serveWasm(
263 });263 });
264 // std.http.Server does not have a sendfile API yet.264 // std.http.Server does not have a sendfile API yet.
265 const bin_path = try wasm_base_path.join(arena, bin_name);265 const bin_path = try wasm_base_path.join(arena, bin_name);
266 const file_contents = try bin_path.root_dir.handle.readFileAlloc(gpa, bin_path.sub_path, 10 * 1024 * 1024);266 const file_contents = try bin_path.root_dir.handle.readFileAlloc(bin_path.sub_path, gpa, .limited(10 * 1024 * 1024));
267 defer gpa.free(file_contents);267 defer gpa.free(file_contents);
268 try request.respond(file_contents, .{268 try request.respond(file_contents, .{
269 .extra_headers = &.{269 .extra_headers = &.{
lib/fuzzer.zig+1-1
...@@ -220,7 +220,7 @@ const Fuzzer = struct {...@@ -220,7 +220,7 @@ const Fuzzer = struct {
220 const i = f.corpus.items.len;220 const i = f.corpus.items.len;
221 var buf: [30]u8 = undefined;221 var buf: [30]u8 = undefined;
222 const input_sub_path = std.fmt.bufPrint(&buf, "{d}", .{i}) catch unreachable;222 const input_sub_path = std.fmt.bufPrint(&buf, "{d}", .{i}) catch unreachable;
223 const input = f.corpus_directory.handle.readFileAlloc(gpa, input_sub_path, 1 << 31) catch |err| switch (err) {223 const input = f.corpus_directory.handle.readFileAlloc(input_sub_path, gpa, .limited(1 << 31)) catch |err| switch (err) {
224 error.FileNotFound => {224 error.FileNotFound => {
225 // Make this one the next input.225 // Make this one the next input.
226 const input_file = f.corpus_directory.handle.createFile(input_sub_path, .{226 const input_file = f.corpus_directory.handle.createFile(input_sub_path, .{
lib/std/Build/Cache.zig+1-1
...@@ -1056,7 +1056,7 @@ pub const Manifest = struct {...@@ -1056,7 +1056,7 @@ pub const Manifest = struct {
10561056
1057 fn addDepFileMaybePost(self: *Manifest, dir: fs.Dir, dep_file_basename: []const u8) !void {1057 fn addDepFileMaybePost(self: *Manifest, dir: fs.Dir, dep_file_basename: []const u8) !void {
1058 const gpa = self.cache.gpa;1058 const gpa = self.cache.gpa;
1059 const dep_file_contents = try dir.readFileAlloc(gpa, dep_file_basename, manifest_file_size_max);1059 const dep_file_contents = try dir.readFileAlloc(dep_file_basename, gpa, .limited(manifest_file_size_max));
1060 defer gpa.free(dep_file_contents);1060 defer gpa.free(dep_file_contents);
10611061
1062 var error_buf: std.ArrayListUnmanaged(u8) = .empty;1062 var error_buf: std.ArrayListUnmanaged(u8) = .empty;
lib/std/Build/Step/CheckFile.zig+1-1
...@@ -53,7 +53,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -53,7 +53,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
53 try step.singleUnchangingWatchInput(check_file.source);53 try step.singleUnchangingWatchInput(check_file.source);
5454
55 const src_path = check_file.source.getPath2(b, step);55 const src_path = check_file.source.getPath2(b, step);
56 const contents = fs.cwd().readFileAlloc(b.allocator, src_path, check_file.max_bytes) catch |err| {56 const contents = fs.cwd().readFileAlloc(src_path, b.allocator, .limited(check_file.max_bytes)) catch |err| {
57 return step.fail("unable to read '{s}': {s}", .{57 return step.fail("unable to read '{s}': {s}", .{
58 src_path, @errorName(err),58 src_path, @errorName(err),
59 });59 });
lib/std/Build/Step/CheckObject.zig+4-5
...@@ -553,14 +553,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {...@@ -553,14 +553,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
553553
554 const src_path = check_object.source.getPath3(b, step);554 const src_path = check_object.source.getPath3(b, step);
555 const contents = src_path.root_dir.handle.readFileAllocOptions(555 const contents = src_path.root_dir.handle.readFileAllocOptions(
556 gpa,
557 src_path.sub_path,556 src_path.sub_path,
558 check_object.max_bytes,557 gpa,
559 null,558 .limited(check_object.max_bytes),
560 .of(u64),559 .of(u64),
561 null,560 null,
562 ) catch |err| return step.fail("unable to read '{f}': {s}", .{561 ) catch |err| return step.fail("unable to read '{f}': {t}", .{
563 std.fmt.alt(src_path, .formatEscapeChar), @errorName(err),562 std.fmt.alt(src_path, .formatEscapeChar), err,
564 });563 });
565564
566 var vars: std.StringHashMap(u64) = .init(gpa);565 var vars: std.StringHashMap(u64) = .init(gpa);
lib/std/Build/Step/ConfigHeader.zig+2-2
...@@ -208,7 +208,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -208,7 +208,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
208 .autoconf_undef, .autoconf_at => |file_source| {208 .autoconf_undef, .autoconf_at => |file_source| {
209 try bw.writeAll(c_generated_line);209 try bw.writeAll(c_generated_line);
210 const src_path = file_source.getPath2(b, step);210 const src_path = file_source.getPath2(b, step);
211 const contents = std.fs.cwd().readFileAlloc(arena, src_path, config_header.max_bytes) catch |err| {211 const contents = std.fs.cwd().readFileAlloc(src_path, arena, .limited(config_header.max_bytes)) catch |err| {
212 return step.fail("unable to read autoconf input file '{s}': {s}", .{212 return step.fail("unable to read autoconf input file '{s}': {s}", .{
213 src_path, @errorName(err),213 src_path, @errorName(err),
214 });214 });
...@@ -222,7 +222,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -222,7 +222,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
222 .cmake => |file_source| {222 .cmake => |file_source| {
223 try bw.writeAll(c_generated_line);223 try bw.writeAll(c_generated_line);
224 const src_path = file_source.getPath2(b, step);224 const src_path = file_source.getPath2(b, step);
225 const contents = std.fs.cwd().readFileAlloc(arena, src_path, config_header.max_bytes) catch |err| {225 const contents = std.fs.cwd().readFileAlloc(src_path, arena, .limited(config_header.max_bytes)) catch |err| {
226 return step.fail("unable to read cmake input file '{s}': {s}", .{226 return step.fail("unable to read cmake input file '{s}': {s}", .{
227 src_path, @errorName(err),227 src_path, @errorName(err),
228 });228 });
lib/std/Build/WebServer.zig+1-1
...@@ -446,7 +446,7 @@ pub fn serveFile(...@@ -446,7 +446,7 @@ pub fn serveFile(
446 // The desired API is actually sendfile, which will require enhancing http.Server.446 // The desired API is actually sendfile, which will require enhancing http.Server.
447 // We load the file with every request so that the user can make changes to the file447 // We load the file with every request so that the user can make changes to the file
448 // and refresh the HTML page without restarting this server.448 // and refresh the HTML page without restarting this server.
449 const file_contents = path.root_dir.handle.readFileAlloc(gpa, path.sub_path, 10 * 1024 * 1024) catch |err| {449 const file_contents = path.root_dir.handle.readFileAlloc(path.sub_path, gpa, .limited(10 * 1024 * 1024)) catch |err| {
450 log.err("failed to read '{f}': {s}", .{ path, @errorName(err) });450 log.err("failed to read '{f}': {s}", .{ path, @errorName(err) });
451 return error.AlreadyReported;451 return error.AlreadyReported;
452 };452 };
lib/std/Io/Reader.zig+41-9
...@@ -292,6 +292,23 @@ pub fn allocRemaining(r: *Reader, gpa: Allocator, limit: Limit) LimitedAllocErro...@@ -292,6 +292,23 @@ pub fn allocRemaining(r: *Reader, gpa: Allocator, limit: Limit) LimitedAllocErro
292 return buffer.toOwnedSlice(gpa);292 return buffer.toOwnedSlice(gpa);
293}293}
294294
295pub fn allocRemainingAlignedSentinel(
296 r: *Reader,
297 gpa: Allocator,
298 limit: Limit,
299 comptime alignment: std.mem.Alignment,
300 comptime sentinel: ?u8,
301) LimitedAllocError!(if (sentinel) |s| [:s]align(alignment.toByteUnits()) u8 else []align(alignment.toByteUnits()) u8) {
302 var buffer: std.array_list.Aligned(u8, alignment) = .empty;
303 defer buffer.deinit(gpa);
304 try appendRemainingAligned(r, gpa, alignment, &buffer, limit);
305 if (sentinel) |s| {
306 return buffer.toOwnedSliceSentinel(gpa, s);
307 } else {
308 return buffer.toOwnedSlice(gpa);
309 }
310}
311
295/// Transfers all bytes from the current position to the end of the stream, up312/// Transfers all bytes from the current position to the end of the stream, up
296/// to `limit`, appending them to `list`.313/// to `limit`, appending them to `list`.
297///314///
...@@ -308,15 +325,30 @@ pub fn appendRemaining(...@@ -308,15 +325,30 @@ pub fn appendRemaining(
308 list: *ArrayList(u8),325 list: *ArrayList(u8),
309 limit: Limit,326 limit: Limit,
310) LimitedAllocError!void {327) LimitedAllocError!void {
311 var a: std.Io.Writer.Allocating = .initOwnedSlice(gpa, list.allocatedSlice());328 return appendRemainingAligned(r, gpa, .of(u8), list, limit);
312 a.writer.end = list.items.len;329}
313 list.* = .empty;330
314 defer {331/// Transfers all bytes from the current position to the end of the stream, up
315 list.* = .{332/// to `limit`, appending them to `list`.
316 .items = a.writer.buffer[0..a.writer.end],333///
317 .capacity = a.writer.buffer.len,334/// If `limit` is reached or exceeded, `error.StreamTooLong` is returned
318 };335/// instead. In such case, the next byte that would be read will be the first
319 }336/// one to exceed `limit`, and all preceeding bytes have been appended to
337/// `list`.
338///
339/// See also:
340/// * `appendRemaining`
341/// * `allocRemainingAligned`
342pub fn appendRemainingAligned(
343 r: *Reader,
344 gpa: Allocator,
345 comptime alignment: std.mem.Alignment,
346 list: *std.array_list.Aligned(u8, alignment),
347 limit: Limit,
348) LimitedAllocError!void {
349 var a = std.Io.Writer.Allocating.fromArrayListAligned(gpa, alignment, list);
350 defer list.* = a.toArrayListAligned(alignment);
351
320 var remaining = limit;352 var remaining = limit;
321 while (remaining.nonzero()) {353 while (remaining.nonzero()) {
322 const n = stream(r, &a.writer, remaining) catch |err| switch (err) {354 const n = stream(r, &a.writer, remaining) catch |err| switch (err) {
lib/std/Io/Writer.zig+118-45
...@@ -2531,13 +2531,14 @@ pub fn Hashing(comptime Hasher: type) type {...@@ -2531,13 +2531,14 @@ pub fn Hashing(comptime Hasher: type) type {
2531/// Maintains `Writer` state such that it writes to the unused capacity of an2531/// Maintains `Writer` state such that it writes to the unused capacity of an
2532/// array list, filling it up completely before making a call through the2532/// array list, filling it up completely before making a call through the
2533/// vtable, causing a resize. Consequently, the same, optimized, non-generic2533/// vtable, causing a resize. Consequently, the same, optimized, non-generic
2534/// machine code that uses `std.Io.Reader`, such as formatted printing, takes2534/// machine code that uses `Writer`, such as formatted printing, takes
2535/// the hot paths when using this API.2535/// the hot paths when using this API.
2536///2536///
2537/// When using this API, it is not necessary to call `flush`.2537/// When using this API, it is not necessary to call `flush`.
2538pub const Allocating = struct {2538pub const Allocating = struct {
2539 allocator: Allocator,2539 allocator: Allocator,
2540 writer: Writer,2540 writer: Writer,
2541 alignment: std.mem.Alignment,
25412542
2542 pub fn init(allocator: Allocator) Allocating {2543 pub fn init(allocator: Allocator) Allocating {
2543 return .{2544 return .{
...@@ -2546,6 +2547,7 @@ pub const Allocating = struct {...@@ -2546,6 +2547,7 @@ pub const Allocating = struct {
2546 .buffer = &.{},2547 .buffer = &.{},
2547 .vtable = &vtable,2548 .vtable = &vtable,
2548 },2549 },
2550 .alignment = .of(u8),
2549 };2551 };
2550 }2552 }
25512553
...@@ -2553,24 +2555,47 @@ pub const Allocating = struct {...@@ -2553,24 +2555,47 @@ pub const Allocating = struct {
2553 return .{2555 return .{
2554 .allocator = allocator,2556 .allocator = allocator,
2555 .writer = .{2557 .writer = .{
2556 .buffer = try allocator.alloc(u8, capacity),2558 .buffer = if (capacity == 0)
2559 &.{}
2560 else
2561 (allocator.rawAlloc(capacity, .of(u8), @returnAddress()) orelse
2562 return error.OutOfMemory)[0..capacity],
2557 .vtable = &vtable,2563 .vtable = &vtable,
2558 },2564 },
2565 .alignment = .of(u8),
2559 };2566 };
2560 }2567 }
25612568
2562 pub fn initOwnedSlice(allocator: Allocator, slice: []u8) Allocating {2569 pub fn initOwnedSlice(allocator: Allocator, slice: []u8) Allocating {
2570 return initOwnedSliceAligned(allocator, .of(u8), slice);
2571 }
2572
2573 pub fn initOwnedSliceAligned(
2574 allocator: Allocator,
2575 comptime alignment: std.mem.Alignment,
2576 slice: []align(alignment.toByteUnits()) u8,
2577 ) Allocating {
2563 return .{2578 return .{
2564 .allocator = allocator,2579 .allocator = allocator,
2565 .writer = .{2580 .writer = .{
2566 .buffer = slice,2581 .buffer = slice,
2567 .vtable = &vtable,2582 .vtable = &vtable,
2568 },2583 },
2584 .alignment = alignment,
2569 };2585 };
2570 }2586 }
25712587
2572 /// Replaces `array_list` with empty, taking ownership of the memory.2588 /// Replaces `array_list` with empty, taking ownership of the memory.
2573 pub fn fromArrayList(allocator: Allocator, array_list: *ArrayList(u8)) Allocating {2589 pub fn fromArrayList(allocator: Allocator, array_list: *ArrayList(u8)) Allocating {
2590 return fromArrayListAligned(allocator, .of(u8), array_list);
2591 }
2592
2593 /// Replaces `array_list` with empty, taking ownership of the memory.
2594 pub fn fromArrayListAligned(
2595 allocator: Allocator,
2596 comptime alignment: std.mem.Alignment,
2597 array_list: *std.array_list.Aligned(u8, alignment),
2598 ) Allocating {
2574 defer array_list.* = .empty;2599 defer array_list.* = .empty;
2575 return .{2600 return .{
2576 .allocator = allocator,2601 .allocator = allocator,
...@@ -2579,6 +2604,7 @@ pub const Allocating = struct {...@@ -2579,6 +2604,7 @@ pub const Allocating = struct {
2579 .buffer = array_list.allocatedSlice(),2604 .buffer = array_list.allocatedSlice(),
2580 .end = array_list.items.len,2605 .end = array_list.items.len,
2581 },2606 },
2607 .alignment = alignment,
2582 };2608 };
2583 }2609 }
25842610
...@@ -2590,15 +2616,26 @@ pub const Allocating = struct {...@@ -2590,15 +2616,26 @@ pub const Allocating = struct {
2590 };2616 };
25912617
2592 pub fn deinit(a: *Allocating) void {2618 pub fn deinit(a: *Allocating) void {
2593 a.allocator.free(a.writer.buffer);2619 if (a.writer.buffer.len == 0) return;
2620 a.allocator.rawFree(a.writer.buffer, a.alignment, @returnAddress());
2594 a.* = undefined;2621 a.* = undefined;
2595 }2622 }
25962623
2597 /// Returns an array list that takes ownership of the allocated memory.2624 /// Returns an array list that takes ownership of the allocated memory.
2598 /// Resets the `Allocating` to an empty state.2625 /// Resets the `Allocating` to an empty state.
2599 pub fn toArrayList(a: *Allocating) ArrayList(u8) {2626 pub fn toArrayList(a: *Allocating) ArrayList(u8) {
2627 return toArrayListAligned(a, .of(u8));
2628 }
2629
2630 /// Returns an array list that takes ownership of the allocated memory.
2631 /// Resets the `Allocating` to an empty state.
2632 pub fn toArrayListAligned(
2633 a: *Allocating,
2634 comptime alignment: std.mem.Alignment,
2635 ) std.array_list.Aligned(u8, alignment) {
2636 assert(a.alignment == alignment); // Required for Allocator correctness.
2600 const w = &a.writer;2637 const w = &a.writer;
2601 const result: ArrayList(u8) = .{2638 const result: std.array_list.Aligned(u8, alignment) = .{
2602 .items = w.buffer[0..w.end],2639 .items = w.buffer[0..w.end],
2603 .capacity = w.buffer.len,2640 .capacity = w.buffer.len,
2604 };2641 };
...@@ -2608,28 +2645,71 @@ pub const Allocating = struct {...@@ -2608,28 +2645,71 @@ pub const Allocating = struct {
2608 }2645 }
26092646
2610 pub fn ensureUnusedCapacity(a: *Allocating, additional_count: usize) Allocator.Error!void {2647 pub fn ensureUnusedCapacity(a: *Allocating, additional_count: usize) Allocator.Error!void {
2611 var list = a.toArrayList();2648 const new_capacity = std.math.add(usize, a.writer.buffer.len, additional_count) catch return error.OutOfMemory;
2612 defer a.setArrayList(list);2649 return ensureTotalCapacity(a, new_capacity);
2613 return list.ensureUnusedCapacity(a.allocator, additional_count);
2614 }2650 }
26152651
2616 pub fn ensureTotalCapacity(a: *Allocating, new_capacity: usize) Allocator.Error!void {2652 pub fn ensureTotalCapacity(a: *Allocating, new_capacity: usize) Allocator.Error!void {
2617 var list = a.toArrayList();2653 return ensureTotalCapacityPrecise(a, ArrayList(u8).growCapacity(a.writer.buffer.len, new_capacity));
2618 defer a.setArrayList(list);
2619 return list.ensureTotalCapacity(a.allocator, new_capacity);
2620 }2654 }
26212655
2622 pub fn toOwnedSlice(a: *Allocating) error{OutOfMemory}![]u8 {2656 pub fn ensureTotalCapacityPrecise(a: *Allocating, new_capacity: usize) Allocator.Error!void {
2623 var list = a.toArrayList();2657 const old_memory = a.writer.buffer;
2624 defer a.setArrayList(list);2658 if (old_memory.len >= new_capacity) return;
2625 return list.toOwnedSlice(a.allocator);2659 assert(new_capacity != 0);
2660 const alignment = a.alignment;
2661 if (old_memory.len > 0) {
2662 if (a.allocator.rawRemap(old_memory, alignment, new_capacity, @returnAddress())) |new| {
2663 a.writer.buffer = new[0..new_capacity];
2664 return;
2665 }
2666 }
2667 const new_memory = (a.allocator.rawAlloc(new_capacity, alignment, @returnAddress()) orelse
2668 return error.OutOfMemory)[0..new_capacity];
2669 const saved = old_memory[0..a.writer.end];
2670 @memcpy(new_memory[0..saved.len], saved);
2671 if (old_memory.len != 0) a.allocator.rawFree(old_memory, alignment, @returnAddress());
2672 a.writer.buffer = new_memory;
2673 }
2674
2675 pub fn toOwnedSlice(a: *Allocating) Allocator.Error![]u8 {
2676 const old_memory = a.writer.buffer;
2677 const alignment = a.alignment;
2678 const buffered_len = a.writer.end;
2679
2680 if (old_memory.len > 0) {
2681 if (buffered_len == 0) {
2682 a.allocator.rawFree(old_memory, alignment, @returnAddress());
2683 a.writer.buffer = &.{};
2684 a.writer.end = 0;
2685 return old_memory[0..0];
2686 } else if (a.allocator.rawRemap(old_memory, alignment, buffered_len, @returnAddress())) |new| {
2687 a.writer.buffer = &.{};
2688 a.writer.end = 0;
2689 return new[0..buffered_len];
2690 }
2691 }
2692
2693 if (buffered_len == 0)
2694 return a.writer.buffer[0..0];
2695
2696 const new_memory = (a.allocator.rawAlloc(buffered_len, alignment, @returnAddress()) orelse
2697 return error.OutOfMemory)[0..buffered_len];
2698 @memcpy(new_memory, old_memory[0..buffered_len]);
2699 if (old_memory.len != 0) a.allocator.rawFree(old_memory, alignment, @returnAddress());
2700 a.writer.buffer = &.{};
2701 a.writer.end = 0;
2702 return new_memory;
2626 }2703 }
26272704
2628 pub fn toOwnedSliceSentinel(a: *Allocating, comptime sentinel: u8) error{OutOfMemory}![:sentinel]u8 {2705 pub fn toOwnedSliceSentinel(a: *Allocating, comptime sentinel: u8) Allocator.Error![:sentinel]u8 {
2629 const gpa = a.allocator;2706 // This addition can never overflow because `a.writer.buffer` can never occupy the whole address space.
2630 var list = @This().toArrayList(a);2707 try ensureTotalCapacityPrecise(a, a.writer.end + 1);
2631 defer a.setArrayList(list);2708 a.writer.buffer[a.writer.end] = sentinel;
2632 return list.toOwnedSliceSentinel(gpa, sentinel);2709 a.writer.end += 1;
2710 errdefer a.writer.end -= 1;
2711 const result = try toOwnedSlice(a);
2712 return result[0 .. result.len - 1 :sentinel];
2633 }2713 }
26342714
2635 pub fn written(a: *Allocating) []u8 {2715 pub fn written(a: *Allocating) []u8 {
...@@ -2646,57 +2726,50 @@ pub const Allocating = struct {...@@ -2646,57 +2726,50 @@ pub const Allocating = struct {
26462726
2647 fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {2727 fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
2648 const a: *Allocating = @fieldParentPtr("writer", w);2728 const a: *Allocating = @fieldParentPtr("writer", w);
2649 const gpa = a.allocator;
2650 const pattern = data[data.len - 1];2729 const pattern = data[data.len - 1];
2651 const splat_len = pattern.len * splat;2730 const splat_len = pattern.len * splat;
2652 var list = a.toArrayList();2731 const start_len = a.writer.end;
2653 defer setArrayList(a, list);
2654 const start_len = list.items.len;
2655 assert(data.len != 0);2732 assert(data.len != 0);
2656 for (data) |bytes| {2733 for (data) |bytes| {
2657 list.ensureUnusedCapacity(gpa, bytes.len + splat_len + 1) catch return error.WriteFailed;2734 a.ensureUnusedCapacity(bytes.len + splat_len + 1) catch return error.WriteFailed;
2658 list.appendSliceAssumeCapacity(bytes);2735 @memcpy(a.writer.buffer[a.writer.end..][0..bytes.len], bytes);
2736 a.writer.end += bytes.len;
2659 }2737 }
2660 if (splat == 0) {2738 if (splat == 0) {
2661 list.items.len -= pattern.len;2739 a.writer.end -= pattern.len;
2662 } else switch (pattern.len) {2740 } else switch (pattern.len) {
2663 0 => {},2741 0 => {},
2664 1 => list.appendNTimesAssumeCapacity(pattern[0], splat - 1),2742 1 => {
2665 else => for (0..splat - 1) |_| list.appendSliceAssumeCapacity(pattern),2743 @memset(a.writer.buffer[a.writer.end..][0 .. splat - 1], pattern[0]);
2744 a.writer.end += splat - 1;
2745 },
2746 else => for (0..splat - 1) |_| {
2747 @memcpy(a.writer.buffer[a.writer.end..][0..pattern.len], pattern);
2748 a.writer.end += pattern.len;
2749 },
2666 }2750 }
2667 return list.items.len - start_len;2751 return a.writer.end - start_len;
2668 }2752 }
26692753
2670 fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {2754 fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
2671 if (File.Handle == void) return error.Unimplemented;2755 if (File.Handle == void) return error.Unimplemented;
2672 if (limit == .nothing) return 0;2756 if (limit == .nothing) return 0;
2673 const a: *Allocating = @fieldParentPtr("writer", w);2757 const a: *Allocating = @fieldParentPtr("writer", w);
2674 const gpa = a.allocator;
2675 var list = a.toArrayList();
2676 defer setArrayList(a, list);
2677 const pos = file_reader.logicalPos();2758 const pos = file_reader.logicalPos();
2678 const additional = if (file_reader.getSize()) |size| size - pos else |_| std.atomic.cache_line;2759 const additional = if (file_reader.getSize()) |size| size - pos else |_| std.atomic.cache_line;
2679 if (additional == 0) return error.EndOfStream;2760 if (additional == 0) return error.EndOfStream;
2680 list.ensureUnusedCapacity(gpa, limit.minInt64(additional)) catch return error.WriteFailed;2761 a.ensureUnusedCapacity(limit.minInt64(additional)) catch return error.WriteFailed;
2681 const dest = limit.slice(list.unusedCapacitySlice());2762 const dest = limit.slice(a.writer.buffer[a.writer.end..]);
2682 const n = try file_reader.read(dest);2763 const n = try file_reader.read(dest);
2683 list.items.len += n;2764 a.writer.end += n;
2684 return n;2765 return n;
2685 }2766 }
26862767
2687 fn growingRebase(w: *Writer, preserve: usize, minimum_len: usize) Error!void {2768 fn growingRebase(w: *Writer, preserve: usize, minimum_len: usize) Error!void {
2688 const a: *Allocating = @fieldParentPtr("writer", w);2769 const a: *Allocating = @fieldParentPtr("writer", w);
2689 const gpa = a.allocator;
2690 var list = a.toArrayList();
2691 defer setArrayList(a, list);
2692 const total = std.math.add(usize, preserve, minimum_len) catch return error.WriteFailed;2770 const total = std.math.add(usize, preserve, minimum_len) catch return error.WriteFailed;
2693 list.ensureTotalCapacity(gpa, total) catch return error.WriteFailed;2771 a.ensureTotalCapacity(total) catch return error.WriteFailed;
2694 list.ensureUnusedCapacity(gpa, minimum_len) catch return error.WriteFailed;2772 a.ensureUnusedCapacity(minimum_len) catch return error.WriteFailed;
2695 }
2696
2697 fn setArrayList(a: *Allocating, list: ArrayList(u8)) void {
2698 a.writer.buffer = list.allocatedSlice();
2699 a.writer.end = list.items.len;
2700 }2773 }
27012774
2702 test Allocating {2775 test Allocating {
lib/std/Thread.zig+1-1
...@@ -282,7 +282,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co...@@ -282,7 +282,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
282 defer file.close();282 defer file.close();
283283
284 var file_reader = file.readerStreaming(&.{});284 var file_reader = file.readerStreaming(&.{});
285 const data_len = file_reader.readSliceShort(buffer_ptr[0 .. max_name_len + 1]) catch |err| switch (err) {285 const data_len = file_reader.interface.readSliceShort(buffer_ptr[0 .. max_name_len + 1]) catch |err| switch (err) {
286 error.ReadFailed => return file_reader.err.?,286 error.ReadFailed => return file_reader.err.?,
287 };287 };
288 return if (data_len >= 1) buffer[0 .. data_len - 1] else null;288 return if (data_len >= 1) buffer[0 .. data_len - 1] else null;
lib/std/array_list.zig+3-2
...@@ -664,9 +664,10 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -664,9 +664,10 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
664664
665 /// The caller owns the returned memory. ArrayList becomes empty.665 /// The caller owns the returned memory. ArrayList becomes empty.
666 pub fn toOwnedSliceSentinel(self: *Self, gpa: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {666 pub fn toOwnedSliceSentinel(self: *Self, gpa: Allocator, comptime sentinel: T) Allocator.Error!SentinelSlice(sentinel) {
667 // This addition can never overflow because `self.items` can never occupy the whole address space667 // This addition can never overflow because `self.items` can never occupy the whole address space.
668 try self.ensureTotalCapacityPrecise(gpa, self.items.len + 1);668 try self.ensureTotalCapacityPrecise(gpa, self.items.len + 1);
669 self.appendAssumeCapacity(sentinel);669 self.appendAssumeCapacity(sentinel);
670 errdefer self.items.len -= 1;
670 const result = try self.toOwnedSlice(gpa);671 const result = try self.toOwnedSlice(gpa);
671 return result[0 .. result.len - 1 :sentinel];672 return result[0 .. result.len - 1 :sentinel];
672 }673 }
...@@ -1361,7 +1362,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {...@@ -1361,7 +1362,7 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
13611362
1362 /// Called when memory growth is necessary. Returns a capacity larger than1363 /// Called when memory growth is necessary. Returns a capacity larger than
1363 /// minimum that grows super-linearly.1364 /// minimum that grows super-linearly.
1364 fn growCapacity(current: usize, minimum: usize) usize {1365 pub fn growCapacity(current: usize, minimum: usize) usize {
1365 var new = current;1366 var new = current;
1366 while (true) {1367 while (true) {
1367 new +|= new / 2 + init_capacity;1368 new +|= new / 2 + init_capacity;
lib/std/debug/Dwarf/expression.zig+4-4
...@@ -851,7 +851,7 @@ pub fn Builder(comptime options: Options) type {...@@ -851,7 +851,7 @@ pub fn Builder(comptime options: Options) type {
851 },851 },
852 .signed => {852 .signed => {
853 try writer.writeByte(OP.consts);853 try writer.writeByte(OP.consts);
854 try leb.writeIleb128(writer, value);854 try writer.writeLeb128(value);
855 },855 },
856 },856 },
857 }857 }
...@@ -885,19 +885,19 @@ pub fn Builder(comptime options: Options) type {...@@ -885,19 +885,19 @@ pub fn Builder(comptime options: Options) type {
885 // 2.5.1.2: Register Values885 // 2.5.1.2: Register Values
886 pub fn writeFbreg(writer: *Writer, offset: anytype) !void {886 pub fn writeFbreg(writer: *Writer, offset: anytype) !void {
887 try writer.writeByte(OP.fbreg);887 try writer.writeByte(OP.fbreg);
888 try leb.writeIleb128(writer, offset);888 try writer.writeSleb128(offset);
889 }889 }
890890
891 pub fn writeBreg(writer: *Writer, register: u8, offset: anytype) !void {891 pub fn writeBreg(writer: *Writer, register: u8, offset: anytype) !void {
892 if (register > 31) return error.InvalidRegister;892 if (register > 31) return error.InvalidRegister;
893 try writer.writeByte(OP.breg0 + register);893 try writer.writeByte(OP.breg0 + register);
894 try leb.writeIleb128(writer, offset);894 try writer.writeSleb128(offset);
895 }895 }
896896
897 pub fn writeBregx(writer: *Writer, register: anytype, offset: anytype) !void {897 pub fn writeBregx(writer: *Writer, register: anytype, offset: anytype) !void {
898 try writer.writeByte(OP.bregx);898 try writer.writeByte(OP.bregx);
899 try writer.writeUleb128(register);899 try writer.writeUleb128(register);
900 try leb.writeIleb128(writer, offset);900 try writer.writeSleb128(offset);
901 }901 }
902902
903 pub fn writeRegvalType(writer: *Writer, register: anytype, offset: anytype) !void {903 pub fn writeRegvalType(writer: *Writer, register: anytype, offset: anytype) !void {
lib/std/fs/Dir.zig+48-30
...@@ -1977,41 +1977,59 @@ pub fn readFile(self: Dir, file_path: []const u8, buffer: []u8) ![]u8 {...@@ -1977,41 +1977,59 @@ pub fn readFile(self: Dir, file_path: []const u8, buffer: []u8) ![]u8 {
1977 return buffer[0..end_index];1977 return buffer[0..end_index];
1978}1978}
19791979
1980/// On success, caller owns returned buffer.1980pub const ReadFileAllocError = File.OpenError || File.ReadError || Allocator.Error || error{
1981/// If the file is larger than `max_bytes`, returns `error.FileTooBig`.1981 /// File size reached or exceeded the provided limit.
1982/// On Windows, `file_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).1982 StreamTooLong,
1983/// On WASI, `file_path` should be encoded as valid UTF-8.1983};
1984/// On other platforms, `file_path` is an opaque sequence of bytes with no particular encoding.1984
1985pub fn readFileAlloc(self: Dir, allocator: mem.Allocator, file_path: []const u8, max_bytes: usize) ![]u8 {1985/// Reads all the bytes from the named file. On success, caller owns returned
1986 return self.readFileAllocOptions(allocator, file_path, max_bytes, null, .of(u8), null);1986/// buffer.
1987///
1988/// If the file size is already known, a better alternative is to initialize a
1989/// `File.Reader`.
1990///
1991/// If the file size cannot be obtained, an error is returned. If
1992/// this is a realistic possibility, a better alternative is to initialize a
1993/// `File.Reader` which handles this seamlessly.
1994pub fn readFileAlloc(
1995 dir: Dir,
1996 /// On Windows, should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
1997 /// On WASI, should be encoded as valid UTF-8.
1998 /// On other platforms, an opaque sequence of bytes with no particular encoding.
1999 sub_path: []const u8,
2000 /// Used to allocate the result.
2001 gpa: Allocator,
2002 /// If reached or exceeded, `error.StreamTooLong` is returned instead.
2003 limit: std.Io.Limit,
2004) ReadFileAllocError![]u8 {
2005 return readFileAllocOptions(dir, sub_path, gpa, limit, .of(u8), null);
1987}2006}
19882007
1989/// On success, caller owns returned buffer.2008/// Reads all the bytes from the named file. On success, caller owns returned
1990/// If the file is larger than `max_bytes`, returns `error.FileTooBig`.2009/// buffer.
1991/// If `size_hint` is specified the initial buffer size is calculated using2010///
1992/// that value, otherwise the effective file size is used instead.2011/// If the file size is already known, a better alternative is to initialize a
1993/// Allows specifying alignment and a sentinel value.2012/// `File.Reader`.
1994/// On Windows, `file_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
1995/// On WASI, `file_path` should be encoded as valid UTF-8.
1996/// On other platforms, `file_path` is an opaque sequence of bytes with no particular encoding.
1997pub fn readFileAllocOptions(2013pub fn readFileAllocOptions(
1998 self: Dir,2014 dir: Dir,
1999 allocator: mem.Allocator,2015 /// On Windows, should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
2000 file_path: []const u8,2016 /// On WASI, should be encoded as valid UTF-8.
2001 max_bytes: usize,2017 /// On other platforms, an opaque sequence of bytes with no particular encoding.
2002 size_hint: ?usize,2018 sub_path: []const u8,
2019 /// Used to allocate the result.
2020 gpa: Allocator,
2021 /// If reached or exceeded, `error.StreamTooLong` is returned instead.
2022 limit: std.Io.Limit,
2003 comptime alignment: std.mem.Alignment,2023 comptime alignment: std.mem.Alignment,
2004 comptime optional_sentinel: ?u8,2024 comptime sentinel: ?u8,
2005) !(if (optional_sentinel) |s| [:s]align(alignment.toByteUnits()) u8 else []align(alignment.toByteUnits()) u8) {2025) ReadFileAllocError!(if (sentinel) |s| [:s]align(alignment.toByteUnits()) u8 else []align(alignment.toByteUnits()) u8) {
2006 var file = try self.openFile(file_path, .{});2026 var file = try dir.openFile(sub_path, .{});
2007 defer file.close();2027 defer file.close();
20082028 var file_reader = file.reader(&.{});
2009 // If the file size doesn't fit a usize it'll be certainly greater than2029 return file_reader.interface.allocRemainingAlignedSentinel(gpa, limit, alignment, sentinel) catch |err| switch (err) {
2010 // `max_bytes`2030 error.ReadFailed => return file_reader.err.?,
2011 const stat_size = size_hint orelse std.math.cast(usize, try file.getEndPos()) orelse2031 error.OutOfMemory, error.StreamTooLong => |e| return e,
2012 return error.FileTooBig;2032 };
2013
2014 return file.readToEndAllocOptions(allocator, max_bytes, stat_size, alignment, optional_sentinel);
2015}2033}
20162034
2017pub const DeleteTreeError = error{2035pub const DeleteTreeError = error{
lib/std/fs/test.zig+35-25
...@@ -676,37 +676,47 @@ test "Dir.realpath smoke test" {...@@ -676,37 +676,47 @@ test "Dir.realpath smoke test" {
676 }.impl);676 }.impl);
677}677}
678678
679test "readAllAlloc" {679test "readFileAlloc" {
680 var tmp_dir = tmpDir(.{});680 var tmp_dir = tmpDir(.{});
681 defer tmp_dir.cleanup();681 defer tmp_dir.cleanup();
682682
683 var file = try tmp_dir.dir.createFile("test_file", .{ .read = true });683 var file = try tmp_dir.dir.createFile("test_file", .{ .read = true });
684 defer file.close();684 defer file.close();
685685
686 const buf1 = try file.readToEndAlloc(testing.allocator, 1024);686 const buf1 = try tmp_dir.dir.readFileAlloc("test_file", testing.allocator, .limited(1024));
687 defer testing.allocator.free(buf1);687 defer testing.allocator.free(buf1);
688 try testing.expectEqual(@as(usize, 0), buf1.len);688 try testing.expectEqualStrings("", buf1);
689689
690 const write_buf: []const u8 = "this is a test.\nthis is a test.\nthis is a test.\nthis is a test.\n";690 const write_buf: []const u8 = "this is a test.\nthis is a test.\nthis is a test.\nthis is a test.\n";
691 try file.writeAll(write_buf);691 try file.writeAll(write_buf);
692 try file.seekTo(0);692
693693 {
694 // max_bytes > file_size694 // max_bytes > file_size
695 const buf2 = try file.readToEndAlloc(testing.allocator, 1024);695 const buf2 = try tmp_dir.dir.readFileAlloc("test_file", testing.allocator, .limited(1024));
696 defer testing.allocator.free(buf2);696 defer testing.allocator.free(buf2);
697 try testing.expectEqual(write_buf.len, buf2.len);697 try testing.expectEqualStrings(write_buf, buf2);
698 try testing.expectEqualStrings(write_buf, buf2);698 }
699 try file.seekTo(0);699
700700 {
701 // max_bytes == file_size701 // max_bytes == file_size
702 const buf3 = try file.readToEndAlloc(testing.allocator, write_buf.len);702 try testing.expectError(
703 defer testing.allocator.free(buf3);703 error.StreamTooLong,
704 try testing.expectEqual(write_buf.len, buf3.len);704 tmp_dir.dir.readFileAlloc("test_file", testing.allocator, .limited(write_buf.len)),
705 try testing.expectEqualStrings(write_buf, buf3);705 );
706 try file.seekTo(0);706 }
707
708 {
709 // max_bytes == file_size + 1
710 const buf2 = try tmp_dir.dir.readFileAlloc("test_file", testing.allocator, .limited(write_buf.len + 1));
711 defer testing.allocator.free(buf2);
712 try testing.expectEqualStrings(write_buf, buf2);
713 }
707714
708 // max_bytes < file_size715 // max_bytes < file_size
709 try testing.expectError(error.FileTooBig, file.readToEndAlloc(testing.allocator, write_buf.len - 1));716 try testing.expectError(
717 error.StreamTooLong,
718 tmp_dir.dir.readFileAlloc("test_file", testing.allocator, .limited(write_buf.len - 1)),
719 );
710}720}
711721
712test "Dir.statFile" {722test "Dir.statFile" {
...@@ -778,16 +788,16 @@ test "file operations on directories" {...@@ -778,16 +788,16 @@ test "file operations on directories" {
778 switch (native_os) {788 switch (native_os) {
779 .dragonfly, .netbsd => {789 .dragonfly, .netbsd => {
780 // no error when reading a directory. See https://github.com/ziglang/zig/issues/5732790 // no error when reading a directory. See https://github.com/ziglang/zig/issues/5732
781 const buf = try ctx.dir.readFileAlloc(testing.allocator, test_dir_name, std.math.maxInt(usize));791 const buf = try ctx.dir.readFileAlloc(test_dir_name, testing.allocator, .unlimited);
782 testing.allocator.free(buf);792 testing.allocator.free(buf);
783 },793 },
784 .wasi => {794 .wasi => {
785 // WASI return EBADF, which gets mapped to NotOpenForReading.795 // WASI return EBADF, which gets mapped to NotOpenForReading.
786 // See https://github.com/bytecodealliance/wasmtime/issues/1935796 // See https://github.com/bytecodealliance/wasmtime/issues/1935
787 try testing.expectError(error.NotOpenForReading, ctx.dir.readFileAlloc(testing.allocator, test_dir_name, std.math.maxInt(usize)));797 try testing.expectError(error.NotOpenForReading, ctx.dir.readFileAlloc(test_dir_name, testing.allocator, .unlimited));
788 },798 },
789 else => {799 else => {
790 try testing.expectError(error.IsDir, ctx.dir.readFileAlloc(testing.allocator, test_dir_name, std.math.maxInt(usize)));800 try testing.expectError(error.IsDir, ctx.dir.readFileAlloc(test_dir_name, testing.allocator, .unlimited));
791 },801 },
792 }802 }
793803
...@@ -1564,7 +1574,7 @@ test "copyFile" {...@@ -1564,7 +1574,7 @@ test "copyFile" {
1564}1574}
15651575
1566fn expectFileContents(dir: Dir, file_path: []const u8, data: []const u8) !void {1576fn expectFileContents(dir: Dir, file_path: []const u8, data: []const u8) !void {
1567 const contents = try dir.readFileAlloc(testing.allocator, file_path, 1000);1577 const contents = try dir.readFileAlloc(file_path, testing.allocator, .limited(1000));
1568 defer testing.allocator.free(contents);1578 defer testing.allocator.free(contents);
15691579
1570 try testing.expectEqualSlices(u8, data, contents);1580 try testing.expectEqualSlices(u8, data, contents);
...@@ -1587,7 +1597,7 @@ test "AtomicFile" {...@@ -1587,7 +1597,7 @@ test "AtomicFile" {
1587 try af.file_writer.interface.writeAll(test_content);1597 try af.file_writer.interface.writeAll(test_content);
1588 try af.finish();1598 try af.finish();
1589 }1599 }
1590 const content = try ctx.dir.readFileAlloc(allocator, test_out_file, 9999);1600 const content = try ctx.dir.readFileAlloc(test_out_file, allocator, .limited(9999));
1591 try testing.expectEqualStrings(test_content, content);1601 try testing.expectEqualStrings(test_content, content);
15921602
1593 try ctx.dir.deleteFile(test_out_file);1603 try ctx.dir.deleteFile(test_out_file);
...@@ -2004,7 +2014,7 @@ test "invalid UTF-8/WTF-8 paths" {...@@ -2004,7 +2014,7 @@ test "invalid UTF-8/WTF-8 paths" {
2004 }2014 }
20052015
2006 try testing.expectError(expected_err, ctx.dir.readFile(invalid_path, &[_]u8{}));2016 try testing.expectError(expected_err, ctx.dir.readFile(invalid_path, &[_]u8{}));
2007 try testing.expectError(expected_err, ctx.dir.readFileAlloc(testing.allocator, invalid_path, 0));2017 try testing.expectError(expected_err, ctx.dir.readFileAlloc(invalid_path, testing.allocator, .limited(0)));
20082018
2009 try testing.expectError(expected_err, ctx.dir.deleteTree(invalid_path));2019 try testing.expectError(expected_err, ctx.dir.deleteTree(invalid_path));
2010 try testing.expectError(expected_err, ctx.dir.deleteTreeMinStackSize(invalid_path));2020 try testing.expectError(expected_err, ctx.dir.deleteTreeMinStackSize(invalid_path));
lib/std/zig/LibCInstallation.zig+1-1
...@@ -43,7 +43,7 @@ pub fn parse(...@@ -43,7 +43,7 @@ pub fn parse(
43 }43 }
44 }44 }
4545
46 const contents = try std.fs.cwd().readFileAlloc(allocator, libc_file, std.math.maxInt(usize));46 const contents = try std.fs.cwd().readFileAlloc(libc_file, allocator, .limited(std.math.maxInt(usize)));
47 defer allocator.free(contents);47 defer allocator.free(contents);
4848
49 var it = std.mem.tokenizeScalar(u8, contents, '\n');49 var it = std.mem.tokenizeScalar(u8, contents, '\n');
lib/std/zig/WindowsSdk.zig+1-1
...@@ -766,7 +766,7 @@ const MsvcLibDir = struct {...@@ -766,7 +766,7 @@ const MsvcLibDir = struct {
766 writer.writeByte(std.fs.path.sep) catch unreachable;766 writer.writeByte(std.fs.path.sep) catch unreachable;
767 writer.writeAll("state.json") catch unreachable;767 writer.writeAll("state.json") catch unreachable;
768768
769 const json_contents = instances_dir.readFileAlloc(allocator, writer.buffered(), std.math.maxInt(usize)) catch continue;769 const json_contents = instances_dir.readFileAlloc(writer.buffered(), allocator, .limited(std.math.maxInt(usize))) catch continue;
770 defer allocator.free(json_contents);770 defer allocator.free(json_contents);
771771
772 var parsed = std.json.parseFromSlice(std.json.Value, allocator, json_contents, .{}) catch continue;772 var parsed = std.json.parseFromSlice(std.json.Value, allocator, json_contents, .{}) catch continue;
src/Compilation.zig+1-1
...@@ -6576,7 +6576,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32...@@ -6576,7 +6576,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
6576 // Read depfile and update cache manifest6576 // Read depfile and update cache manifest
6577 {6577 {
6578 const dep_basename = fs.path.basename(out_dep_path);6578 const dep_basename = fs.path.basename(out_dep_path);
6579 const dep_file_contents = try zig_cache_tmp_dir.readFileAlloc(arena, dep_basename, 50 * 1024 * 1024);6579 const dep_file_contents = try zig_cache_tmp_dir.readFileAlloc(dep_basename, arena, .limited(50 * 1024 * 1024));
6580 defer arena.free(dep_file_contents);6580 defer arena.free(dep_file_contents);
65816581
6582 const value = try std.json.parseFromSliceLeaky(std.json.Value, arena, dep_file_contents, .{});6582 const value = try std.json.parseFromSliceLeaky(std.json.Value, arena, dep_file_contents, .{});
src/Package/Fetch.zig+2-3
...@@ -655,10 +655,9 @@ fn loadManifest(f: *Fetch, pkg_root: Cache.Path) RunError!void {...@@ -655,10 +655,9 @@ fn loadManifest(f: *Fetch, pkg_root: Cache.Path) RunError!void {
655 const eb = &f.error_bundle;655 const eb = &f.error_bundle;
656 const arena = f.arena.allocator();656 const arena = f.arena.allocator();
657 const manifest_bytes = pkg_root.root_dir.handle.readFileAllocOptions(657 const manifest_bytes = pkg_root.root_dir.handle.readFileAllocOptions(
658 arena,
659 try fs.path.join(arena, &.{ pkg_root.sub_path, Manifest.basename }),658 try fs.path.join(arena, &.{ pkg_root.sub_path, Manifest.basename }),
660 Manifest.max_bytes,659 arena,
661 null,660 .limited(Manifest.max_bytes),
662 .@"1",661 .@"1",
663 0,662 0,
664 ) catch |err| switch (err) {663 ) catch |err| switch (err) {
src/Package/Fetch/git.zig+2-2
...@@ -1599,7 +1599,7 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void...@@ -1599,7 +1599,7 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void
1599 const max_file_size = 8192;1599 const max_file_size = 8192;
16001600
1601 if (!skip_checksums) {1601 if (!skip_checksums) {
1602 const index_file_data = try git_dir.dir.readFileAlloc(testing.allocator, "testrepo.idx", max_file_size);1602 const index_file_data = try git_dir.dir.readFileAlloc("testrepo.idx", testing.allocator, .limited(max_file_size));
1603 defer testing.allocator.free(index_file_data);1603 defer testing.allocator.free(index_file_data);
1604 // testrepo.idx is generated by Git. The index created by this file should1604 // testrepo.idx is generated by Git. The index created by this file should
1605 // match it exactly. Running `git verify-pack -v testrepo.pack` can verify1605 // match it exactly. Running `git verify-pack -v testrepo.pack` can verify
...@@ -1675,7 +1675,7 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void...@@ -1675,7 +1675,7 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void
1675 \\revision 191675 \\revision 19
1676 \\1676 \\
1677 ;1677 ;
1678 const actual_file_contents = try worktree.dir.readFileAlloc(testing.allocator, "file", max_file_size);1678 const actual_file_contents = try worktree.dir.readFileAlloc("file", testing.allocator, .limited(max_file_size));
1679 defer testing.allocator.free(actual_file_contents);1679 defer testing.allocator.free(actual_file_contents);
1680 try testing.expectEqualStrings(expected_file_contents, actual_file_contents);1680 try testing.expectEqualStrings(expected_file_contents, actual_file_contents);
1681}1681}
src/link/MachO.zig+1-1
...@@ -4361,7 +4361,7 @@ fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersi...@@ -4361,7 +4361,7 @@ fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersi
4361// The file/property is also available with vendored libc.4361// The file/property is also available with vendored libc.
4362fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 {4362fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 {
4363 const sdk_path = try fs.path.join(arena, &.{ dir, "SDKSettings.json" });4363 const sdk_path = try fs.path.join(arena, &.{ dir, "SDKSettings.json" });
4364 const contents = try fs.cwd().readFileAlloc(arena, sdk_path, std.math.maxInt(u16));4364 const contents = try fs.cwd().readFileAlloc(sdk_path, arena, .limited(std.math.maxInt(u16)));
4365 const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{});4365 const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{});
4366 if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string;4366 if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string;
4367 return error.SdkVersionFailure;4367 return error.SdkVersionFailure;
src/link/MachO/dyld_info/bind.zig+1-1
...@@ -647,7 +647,7 @@ fn setDylibOrdinal(ordinal: i16, writer: *std.Io.Writer) !void {...@@ -647,7 +647,7 @@ fn setDylibOrdinal(ordinal: i16, writer: *std.Io.Writer) !void {
647fn setAddend(addend: i64, writer: *std.Io.Writer) !void {647fn setAddend(addend: i64, writer: *std.Io.Writer) !void {
648 log.debug(">>> set addend: {x}", .{addend});648 log.debug(">>> set addend: {x}", .{addend});
649 try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);649 try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
650 try std.leb.writeIleb128(writer, addend);650 try writer.writeSleb128(addend);
651}651}
652652
653fn doBind(writer: *std.Io.Writer) !void {653fn doBind(writer: *std.Io.Writer) !void {
src/main.zig+5-6
...@@ -5443,7 +5443,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -5443,7 +5443,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
5443 // that are missing.5443 // that are missing.
5444 const s = fs.path.sep_str;5444 const s = fs.path.sep_str;
5445 const tmp_sub_path = "tmp" ++ s ++ results_tmp_file_nonce;5445 const tmp_sub_path = "tmp" ++ s ++ results_tmp_file_nonce;
5446 const stdout = dirs.local_cache.handle.readFileAlloc(arena, tmp_sub_path, 50 * 1024 * 1024) catch |err| {5446 const stdout = dirs.local_cache.handle.readFileAlloc(tmp_sub_path, arena, .limited(50 * 1024 * 1024)) catch |err| {
5447 fatal("unable to read results of configure phase from '{f}{s}': {s}", .{5447 fatal("unable to read results of configure phase from '{f}{s}': {s}", .{
5448 dirs.local_cache, tmp_sub_path, @errorName(err),5448 dirs.local_cache, tmp_sub_path, @errorName(err),
5449 });5449 });
...@@ -5826,7 +5826,7 @@ const ArgIteratorResponseFile = process.ArgIteratorGeneral(.{ .comments = true,...@@ -5826,7 +5826,7 @@ const ArgIteratorResponseFile = process.ArgIteratorGeneral(.{ .comments = true,
5826/// Initialize the arguments from a Response File. "*.rsp"5826/// Initialize the arguments from a Response File. "*.rsp"
5827fn initArgIteratorResponseFile(allocator: Allocator, resp_file_path: []const u8) !ArgIteratorResponseFile {5827fn initArgIteratorResponseFile(allocator: Allocator, resp_file_path: []const u8) !ArgIteratorResponseFile {
5828 const max_bytes = 10 * 1024 * 1024; // 10 MiB of command line arguments is a reasonable limit5828 const max_bytes = 10 * 1024 * 1024; // 10 MiB of command line arguments is a reasonable limit
5829 const cmd_line = try fs.cwd().readFileAlloc(allocator, resp_file_path, max_bytes);5829 const cmd_line = try fs.cwd().readFileAlloc(resp_file_path, allocator, .limited(max_bytes));
5830 errdefer allocator.free(cmd_line);5830 errdefer allocator.free(cmd_line);
58315831
5832 return ArgIteratorResponseFile.initTakeOwnership(allocator, cmd_line);5832 return ArgIteratorResponseFile.initTakeOwnership(allocator, cmd_line);
...@@ -7350,10 +7350,9 @@ fn loadManifest(...@@ -7350,10 +7350,9 @@ fn loadManifest(
7350) !struct { Package.Manifest, Ast } {7350) !struct { Package.Manifest, Ast } {
7351 const manifest_bytes = while (true) {7351 const manifest_bytes = while (true) {
7352 break options.dir.readFileAllocOptions(7352 break options.dir.readFileAllocOptions(
7353 arena,
7354 Package.Manifest.basename,7353 Package.Manifest.basename,
7355 Package.Manifest.max_bytes,7354 arena,
7356 null,7355 .limited(Package.Manifest.max_bytes),
7357 .@"1",7356 .@"1",
7358 0,7357 0,
7359 ) catch |err| switch (err) {7358 ) catch |err| switch (err) {
...@@ -7435,7 +7434,7 @@ const Templates = struct {...@@ -7435,7 +7434,7 @@ const Templates = struct {
7435 }7434 }
74367435
7437 const max_bytes = 10 * 1024 * 1024;7436 const max_bytes = 10 * 1024 * 1024;
7438 const contents = templates.dir.readFileAlloc(arena, template_path, max_bytes) catch |err| {7437 const contents = templates.dir.readFileAlloc(template_path, arena, .limited(max_bytes)) catch |err| {
7439 fatal("unable to read template file '{s}': {s}", .{ template_path, @errorName(err) });7438 fatal("unable to read template file '{s}': {s}", .{ template_path, @errorName(err) });
7440 };7439 };
7441 templates.buffer.clearRetainingCapacity();7440 templates.buffer.clearRetainingCapacity();
src/print_targets.zig+2-2
...@@ -24,9 +24,9 @@ pub fn cmdTargets(...@@ -24,9 +24,9 @@ pub fn cmdTargets(
24 defer allocator.free(zig_lib_directory.path.?);24 defer allocator.free(zig_lib_directory.path.?);
2525
26 const abilists_contents = zig_lib_directory.handle.readFileAlloc(26 const abilists_contents = zig_lib_directory.handle.readFileAlloc(
27 allocator,
28 glibc.abilists_path,27 glibc.abilists_path,
29 glibc.abilists_max_size,28 allocator,
29 .limited(glibc.abilists_max_size),
30 ) catch |err| switch (err) {30 ) catch |err| switch (err) {
31 error.OutOfMemory => return error.OutOfMemory,31 error.OutOfMemory => return error.OutOfMemory,
32 else => fatal("unable to read " ++ glibc.abilists_path ++ ": {s}", .{@errorName(err)}),32 else => fatal("unable to read " ++ glibc.abilists_path ++ ": {s}", .{@errorName(err)}),