Skip to content

Commit adec767

Browse files
committed
[Concurrency] Have StackAllocator gracefully fail when passed a small firstSlabBuffer.
Creating a task for an async let will attempt to allocate the task in the async let's preallocated space, and if there's any space left over then it will use the extra for the new tasks's allocator. However, StackAllocator requires the preallocated buffer to be large enough to hold a slab header, but the task creation code doesn't check for that. As a result, the task creation code can end up passing a buffer that's too small to hold the slab header. When asserts are enabled, this is caught by an assert. When asserts are not enabled, disaster strikes. We end up computing a negative number for the remaining slab capacity, which underflows to a large positive number, causing the slab to overflow the async let's preallocated space. This results in weird memory corruption. SR-15996 rdar://90357994
1 parent cb082e1 commit adec767

File tree

1 file changed

+4
-1
lines changed

1 file changed

+4
-1
lines changed

stdlib/public/runtime/StackAllocator.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,10 @@ class StackAllocator {
283283
numAllocatedSlabs(0) {}
284284

285285
/// Construct a StackAllocator with a pre-allocated first slab.
286-
StackAllocator(void *firstSlabBuffer, size_t bufferCapacity) {
286+
StackAllocator(void *firstSlabBuffer, size_t bufferCapacity) : StackAllocator() {
287+
// If the pre-allocated buffer can't hold a slab header, ignore it.
288+
if (bufferCapacity <= Slab::headerSize())
289+
return;
287290
char *start = (char *)llvm::alignAddr(firstSlabBuffer,
288291
llvm::Align(alignment));
289292
char *end = (char *)firstSlabBuffer + bufferCapacity;

0 commit comments

Comments
 (0)