authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-12-14 16:03:44+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-09 17:18:20-08:00
log828d23956d44b71f8b2394c6d7ab08c23d22fcc3
tree53c358e0ac6d2f81c4191527bd8fb2e4bcabf178
parent6a32d58876995f18b35ffd89b8875a99417c29cf

std.heap: add runtime safety for calling `stackFallback(N).get` multiple times

Closes #16344

2 files changed, 38 insertions(+), 13 deletions(-)

deps/aro/aro/Compilation.zig+10-6
...@@ -1350,9 +1350,10 @@ pub fn hasInclude(...@@ -1350,9 +1350,10 @@ pub fn hasInclude(
1350 }1350 }
13511351
1352 var stack_fallback = std.heap.stackFallback(path_buf_stack_limit, comp.gpa);1352 var stack_fallback = std.heap.stackFallback(path_buf_stack_limit, comp.gpa);
1353 const sf_allocator = stack_fallback.get();
13531354
1354 while (try it.nextWithFile(filename, stack_fallback.get())) |found| {1355 while (try it.nextWithFile(filename, sf_allocator)) |found| {
1355 defer stack_fallback.get().free(found.path);1356 defer sf_allocator.free(found.path);
1356 if (!std.meta.isError(cwd.access(found.path, .{}))) return true;1357 if (!std.meta.isError(cwd.access(found.path, .{}))) return true;
1357 }1358 }
1358 return false;1359 return false;
...@@ -1411,9 +1412,10 @@ pub fn findEmbed(...@@ -1411,9 +1412,10 @@ pub fn findEmbed(
1411 };1412 };
1412 var it = IncludeDirIterator{ .comp = comp, .cwd_source_id = cwd_source_id };1413 var it = IncludeDirIterator{ .comp = comp, .cwd_source_id = cwd_source_id };
1413 var stack_fallback = std.heap.stackFallback(path_buf_stack_limit, comp.gpa);1414 var stack_fallback = std.heap.stackFallback(path_buf_stack_limit, comp.gpa);
1415 const sf_allocator = stack_fallback.get();
14141416
1415 while (try it.nextWithFile(filename, stack_fallback.get())) |found| {1417 while (try it.nextWithFile(filename, sf_allocator)) |found| {
1416 defer stack_fallback.get().free(found.path);1418 defer sf_allocator.free(found.path);
1417 if (comp.getFileContents(found.path, limit)) |some|1419 if (comp.getFileContents(found.path, limit)) |some|
1418 return some1420 return some
1419 else |err| switch (err) {1421 else |err| switch (err) {
...@@ -1457,8 +1459,10 @@ pub fn findInclude(...@@ -1457,8 +1459,10 @@ pub fn findInclude(
1457 }1459 }
14581460
1459 var stack_fallback = std.heap.stackFallback(path_buf_stack_limit, comp.gpa);1461 var stack_fallback = std.heap.stackFallback(path_buf_stack_limit, comp.gpa);
1460 while (try it.nextWithFile(filename, stack_fallback.get())) |found| {1462 const sf_allocator = stack_fallback.get();
1461 defer stack_fallback.get().free(found.path);1463
1464 while (try it.nextWithFile(filename, sf_allocator)) |found| {
1465 defer sf_allocator.free(found.path);
1462 if (comp.addSourceFromPathExtra(found.path, found.kind)) |some| {1466 if (comp.addSourceFromPathExtra(found.path, found.kind)) |some| {
1463 if (it.tried_ms_cwd) {1467 if (it.tried_ms_cwd) {
1464 try comp.addDiagnostic(.{1468 try comp.addDiagnostic(.{
lib/std/heap.zig+28-7
...@@ -521,10 +521,16 @@ pub fn StackFallbackAllocator(comptime size: usize) type {...@@ -521,10 +521,16 @@ pub fn StackFallbackAllocator(comptime size: usize) type {
521 buffer: [size]u8,521 buffer: [size]u8,
522 fallback_allocator: Allocator,522 fallback_allocator: Allocator,
523 fixed_buffer_allocator: FixedBufferAllocator,523 fixed_buffer_allocator: FixedBufferAllocator,
524 get_called: if (std.debug.runtime_safety) bool else void =
525 if (std.debug.runtime_safety) false else {},
524526
525 /// This function both fetches a `Allocator` interface to this527 /// This function both fetches a `Allocator` interface to this
526 /// allocator *and* resets the internal buffer allocator.528 /// allocator *and* resets the internal buffer allocator.
527 pub fn get(self: *Self) Allocator {529 pub fn get(self: *Self) Allocator {
530 if (std.debug.runtime_safety) {
531 assert(!self.get_called); // `get` called multiple times; instead use `const allocator = stackFallback(N).get();`
532 self.get_called = true;
533 }
528 self.fixed_buffer_allocator = FixedBufferAllocator.init(self.buffer[0..]);534 self.fixed_buffer_allocator = FixedBufferAllocator.init(self.buffer[0..]);
529 return .{535 return .{
530 .ptr = self,536 .ptr = self,
...@@ -536,6 +542,12 @@ pub fn StackFallbackAllocator(comptime size: usize) type {...@@ -536,6 +542,12 @@ pub fn StackFallbackAllocator(comptime size: usize) type {
536 };542 };
537 }543 }
538544
545 /// Unlike most std allocators `StackFallbackAllocator` modifies
546 /// its internal state before returning an implementation of
547 /// the`Allocator` interface and therefore also doesn't use
548 /// the usual `.allocator()` method.
549 pub const allocator = @compileError("use 'const allocator = stackFallback(N).get();' instead");
550
539 fn alloc(551 fn alloc(
540 ctx: *anyopaque,552 ctx: *anyopaque,
541 len: usize,553 len: usize,
...@@ -675,13 +687,22 @@ test "FixedBufferAllocator.reset" {...@@ -675,13 +687,22 @@ test "FixedBufferAllocator.reset" {
675}687}
676688
677test "StackFallbackAllocator" {689test "StackFallbackAllocator" {
678 const fallback_allocator = page_allocator;690 {
679 var stack_allocator = stackFallback(4096, fallback_allocator);691 var stack_allocator = stackFallback(4096, std.testing.allocator);
680692 try testAllocator(stack_allocator.get());
681 try testAllocator(stack_allocator.get());693 }
682 try testAllocatorAligned(stack_allocator.get());694 {
683 try testAllocatorLargeAlignment(stack_allocator.get());695 var stack_allocator = stackFallback(4096, std.testing.allocator);
684 try testAllocatorAlignedShrink(stack_allocator.get());696 try testAllocatorAligned(stack_allocator.get());
697 }
698 {
699 var stack_allocator = stackFallback(4096, std.testing.allocator);
700 try testAllocatorLargeAlignment(stack_allocator.get());
701 }
702 {
703 var stack_allocator = stackFallback(4096, std.testing.allocator);
704 try testAllocatorAlignedShrink(stack_allocator.get());
705 }
685}706}
686707
687test "FixedBufferAllocator Reuse memory on realloc" {708test "FixedBufferAllocator Reuse memory on realloc" {