Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Protect against accounting overflow in Arena allocation
This change protects against large allocations causing Arena's internal size accounting to overflow and produce incorrect results. This overflow could allow for invalid offsets being returned from `Arena.Alloc`, leading to slice bounds and index out of range panics when passed to `Arena.GetBytes` or `Arena.GetPointer`. Specifically, if `Arena.n` overflowed in `Arena.Alloc`, which was possible because it was a uint32 and we allow up to MaxUint32 size allocations, then `Arena.Alloc` could bypass the length check against `Arena.buf`. The "padded" size would then be subtracted from the offset, allowing the offset to underflow back around to an offset that was out of `Arena.buf`'s bounds. I believe this is the underlying cause of the following two crashes: - cockroachdb/cockroach#31624 - cockroachdb/cockroach#35557 The reason for this is subtle and has to do with failed allocations slowly building up and eventually overflowing `Arena.n`. I'll explain on the PR that vendors this fix. We now protect against this overflow in two ways. We perform an initial size check before performing the atomic addition in `Arena.Alloc` to prevent failed allocations from "building up" to an overflow. We also use 64-bit arithmetic so that it would take 2^32 concurrent allocations with the maximum allocation size (math.MaxUint32) to overflow the accounting. An alternative would be to use a CAS loop to strictly serialize all additions to `Arena.n`, but that would limit concurrency.
- Loading branch information