| ... | @@ -561,24 +561,25 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { | ... | @@ -561,24 +561,25 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 561 | return error.OutOfMemory; | 561 | return error.OutOfMemory; |
| 562 | } | 562 | } |
| 563 | | 563 | |
| | 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 | |
| 564 | fn alloc(allocator: *Allocator, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) Error![]u8 { | 577 | fn alloc(allocator: *Allocator, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) Error![]u8 { |
| 565 | const self = @fieldParentPtr(Self, "allocator", allocator); | 578 | const self = @fieldParentPtr(Self, "allocator", allocator); |
| 566 | | 579 | |
| 567 | const held = self.mutex.acquire(); | 580 | const held = self.mutex.acquire(); |
| 568 | defer held.release(); | 581 | defer held.release(); |
| 569 | | 582 | |
| 570 | const prev_req_bytes = self.total_requested_bytes; | | |
| 571 | if (config.enable_memory_limit) { | | |
| 572 | const new_req_bytes = prev_req_bytes + len; | | |
| 573 | if (new_req_bytes > self.requested_memory_limit) { | | |
| 574 | return error.OutOfMemory; | | |
| 575 | } | | |
| 576 | self.total_requested_bytes = new_req_bytes; | | |
| 577 | } | | |
| 578 | errdefer if (config.enable_memory_limit) { | | |
| 579 | self.total_requested_bytes = prev_req_bytes; | | |
| 580 | }; | | |
| 581 | | | |
| 582 | const new_aligned_size = math.max(len, ptr_align); | 583 | const new_aligned_size = math.max(len, ptr_align); |
| 583 | if (new_aligned_size > largest_bucket_object_size) { | 584 | if (new_aligned_size > largest_bucket_object_size) { |
| 584 | try self.large_allocations.ensureCapacity( | 585 | try self.large_allocations.ensureCapacity( |
| ... | @@ -588,17 +589,30 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { | ... | @@ -588,17 +589,30 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 588 | | 589 | |
| 589 | const slice = try self.backing_allocator.allocFn(self.backing_allocator, len, ptr_align, len_align, ret_addr); | 590 | const slice = try self.backing_allocator.allocFn(self.backing_allocator, len, ptr_align, len_align, ret_addr); |
| 590 | | 591 | |
| | 592 | // The backing allocator may return a memory block bigger than |
| | 593 | // `len`, use the effective size for bookkeeping purposes |
| | 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); |
| | 598 | return error.OutOfMemory; |
| | 599 | } |
| | 600 | |
| 591 | const gop = self.large_allocations.getOrPutAssumeCapacity(@ptrToInt(slice.ptr)); | 601 | const gop = self.large_allocations.getOrPutAssumeCapacity(@ptrToInt(slice.ptr)); |
| 592 | assert(!gop.found_existing); // This would mean the kernel double-mapped pages. | 602 | assert(!gop.found_existing); // This would mean the kernel double-mapped pages. |
| 593 | gop.entry.value.bytes = slice; | 603 | gop.entry.value.bytes = slice; |
| 594 | collectStackTrace(ret_addr, &gop.entry.value.stack_addresses); | 604 | collectStackTrace(ret_addr, &gop.entry.value.stack_addresses); |
| 595 | | 605 | |
| 596 | return slice; | 606 | return slice; |
| 597 | } else { | | |
| 598 | const new_size_class = math.ceilPowerOfTwoAssert(usize, new_aligned_size); | | |
| 599 | const ptr = try self.allocSlot(new_size_class, ret_addr); | | |
| 600 | return ptr[0..len]; | | |
| 601 | } | 607 | } |
| | 608 | |
| | 609 | if (!self.isAllocationAllowed(len)) { |
| | 610 | return error.OutOfMemory; |
| | 611 | } |
| | 612 | |
| | 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]; |
| 602 | } | 616 | } |
| 603 | | 617 | |
| 604 | fn createBucket(self: *Self, size_class: usize, bucket_index: usize) Error!*BucketHeader { | 618 | fn createBucket(self: *Self, size_class: usize, bucket_index: usize) Error!*BucketHeader { |