authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-08-31 12:35:25+02:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-08-31 12:35:25+02:00
log29de809a92cdc243149fd26a8f3c50180fc33ed5
tree327223ce6050556d1a51685826843b93d744b255
parentf20305d249af89d266fc87b353164e2e7c056580

gpa: Don't leak memory when the upper bound is hit


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

lib/std/heap/general_purpose_allocator.zig+37-25
......@@ -561,6 +561,19 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
561561 return error.OutOfMemory;
562562 }
563563
564 // Returns true if an allocation of `size` bytes is within the specified
565 // limits if enable_memory_limit is true
566 fn isAllocationAllowed(self: *Self, size: usize) bool {
567 if (config.enable_memory_limit) {
568 const new_req_bytes = self.total_requested_bytes + size;
569 if (new_req_bytes > self.requested_memory_limit)
570 return false;
571 self.total_requested_bytes = new_req_bytes;
572 }
573
574 return true;
575 }
576
564577 fn alloc(allocator: *Allocator, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) Error![]u8 {
565578 const self = @fieldParentPtr(Self, "allocator", allocator);
566579
......@@ -568,39 +581,38 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
568581 defer held.release();
569582
570583 const new_aligned_size = math.max(len, ptr_align);
571 const mem_slice = blk: {
572 if (new_aligned_size > largest_bucket_object_size) {
573 try self.large_allocations.ensureCapacity(
574 self.backing_allocator,
575 self.large_allocations.entries.items.len + 1,
576 );
577
578 const slice = try self.backing_allocator.allocFn(self.backing_allocator, len, ptr_align, len_align, ret_addr);
584 if (new_aligned_size > largest_bucket_object_size) {
585 try self.large_allocations.ensureCapacity(
586 self.backing_allocator,
587 self.large_allocations.entries.items.len + 1,
588 );
579589
580 const gop = self.large_allocations.getOrPutAssumeCapacity(@ptrToInt(slice.ptr));
581 assert(!gop.found_existing); // This would mean the kernel double-mapped pages.
582 gop.entry.value.bytes = slice;
583 collectStackTrace(ret_addr, &gop.entry.value.stack_addresses);
584
585 break :blk slice;
586 } else {
587 const new_size_class = math.ceilPowerOfTwoAssert(usize, new_aligned_size);
588 const ptr = try self.allocSlot(new_size_class, ret_addr);
589 break :blk ptr[0..len];
590 }
591 };
590 const slice = try self.backing_allocator.allocFn(self.backing_allocator, len, ptr_align, len_align, ret_addr);
592591
593 if (config.enable_memory_limit) {
594592 // The backing allocator may return a memory block bigger than
595593 // `len`, use the effective size for bookkeeping purposes
596 const new_req_bytes = self.total_requested_bytes + mem_slice.len;
597 if (new_req_bytes > self.requested_memory_limit) {
594 if (!self.isAllocationAllowed(slice.len)) {
595 // Free the block so no memory is leaked
596 const new_len = try self.backing_allocator.resizeFn(self.backing_allocator, slice, ptr_align, 0, 0, ret_addr);
597 assert(new_len == 0);
598598 return error.OutOfMemory;
599599 }
600 self.total_requested_bytes = new_req_bytes;
600
601 const gop = self.large_allocations.getOrPutAssumeCapacity(@ptrToInt(slice.ptr));
602 assert(!gop.found_existing); // This would mean the kernel double-mapped pages.
603 gop.entry.value.bytes = slice;
604 collectStackTrace(ret_addr, &gop.entry.value.stack_addresses);
605
606 return slice;
607 }
608
609 if (!self.isAllocationAllowed(len)) {
610 return error.OutOfMemory;
601611 }
602612
603 return mem_slice;
613 const new_size_class = math.ceilPowerOfTwoAssert(usize, new_aligned_size);
614 const ptr = try self.allocSlot(new_size_class, ret_addr);
615 return ptr[0..len];
604616 }
605617
606618 fn createBucket(self: *Self, size_class: usize, bucket_index: usize) Error!*BucketHeader {