Skip to content

Commit 805882b

Browse files
committed
Handle that posix_memalign differs from aligned_alloc for size == 0
1 parent 05f6b92 commit 805882b

File tree

1 file changed

+20
-10
lines changed

1 file changed

+20
-10
lines changed

src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeMemory.Unix.cs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,18 @@ public static unsafe partial class NativeMemory
3232
// The C standard and POSIX requires size to be a multiple of alignment and we want an "empty" allocation for zero
3333
// POSIX additionally requires alignment to be at least sizeof(void*)
3434

35-
// The adjustment for byteCount can overflow here, but such overflow is "harmless". This is because of the requirement
36-
// that alignment be a power of two and that byteCount be a multiple of alignment. Given both of these constraints
37-
// we should only overflow for byteCount > (nuint.MaxValue & ~(alignment - 1)). When such an overflow occurs we will
38-
// get a result that is less than alignment which will cause the allocation to fail.
35+
// The adjustment for byteCount can overflow here, and such overflow is generally "harmless". This is because of the
36+
// requirement that alignment be a power of two and that byteCount be a multiple of alignment. Given both of these
37+
// constraints we should only overflow for byteCount > (nuint.MaxValue & ~(alignment - 1)). When such an overflow
38+
// occurs we will get a result that is less than alignment which will cause the allocation to fail.
39+
//
40+
// However, posix_memalign differs from aligned_alloc in that it may return a valid pointer for zero and we need to
41+
// ensure we OOM for this scenario (which can occur for `nuint.MaxValue`) and so we have to check the adjusted size.
3942

4043
nuint adjustedAlignment = Math.Max(alignment, (uint)sizeof(void*));
41-
void* result = Interop.Sys.AlignedAlloc(adjustedAlignment, (byteCount != 0) ? (byteCount + (adjustedAlignment - 1)) & ~(adjustedAlignment - 1) : adjustedAlignment);
44+
nuint adjustedByteCount = (byteCount != 0) ? (byteCount + (adjustedAlignment - 1)) & ~(adjustedAlignment - 1) : adjustedAlignment;
45+
46+
void* result = (adjustedByteCount < byteCount) ? null : Interop.Sys.AlignedAlloc(adjustedAlignment, adjustedByteCount);
4247

4348
if (result == null)
4449
{
@@ -88,13 +93,18 @@ public static void AlignedFree(void* ptr)
8893
// The C standard and POSIX requires size to be a multiple of alignment and we want an "empty" allocation for zero
8994
// POSIX additionally requires alignment to be at least sizeof(void*)
9095

91-
// The adjustment for byteCount can overflow here, but such overflow is "harmless". This is because of the requirement
92-
// that alignment be a power of two and that byteCount be a multiple of alignment. Given both of these constraints
93-
// we should only overflow for byteCount > (nuint.MaxValue & ~(alignment - 1)). When such an overflow occurs we will
94-
// get a result that is less than alignment which will cause the allocation to fail.
96+
// The adjustment for byteCount can overflow here, and such overflow is generally "harmless". This is because of the
97+
// requirement that alignment be a power of two and that byteCount be a multiple of alignment. Given both of these
98+
// constraints we should only overflow for byteCount > (nuint.MaxValue & ~(alignment - 1)). When such an overflow
99+
// occurs we will get a result that is less than alignment which will cause the allocation to fail.
100+
//
101+
// However, posix_memalign differs from aligned_alloc in that it may return a valid pointer for zero and we need to
102+
// ensure we OOM for this scenario (which can occur for `nuint.MaxValue`) and so we have to check the adjusted size.
95103

96104
nuint adjustedAlignment = Math.Max(alignment, (uint)sizeof(void*));
97-
void* result = Interop.Sys.AlignedRealloc(ptr, adjustedAlignment, (byteCount != 0) ? (byteCount + (adjustedAlignment - 1)) & ~(adjustedAlignment - 1) : adjustedAlignment);
105+
nuint adjustedByteCount = (byteCount != 0) ? (byteCount + (adjustedAlignment - 1)) & ~(adjustedAlignment - 1) : adjustedAlignment;
106+
107+
void* result = (adjustedByteCount < byteCount) ? null : Interop.Sys.AlignedRealloc(ptr, adjustedAlignment, adjustedByteCount);
98108

99109
if (result == null)
100110
{

0 commit comments

Comments
 (0)