Skip to content

Commit 12e3b62

Browse files
committed
Unify behavior across platforms
1 parent e062e5a commit 12e3b62

File tree

4 files changed

+18
-34
lines changed

4 files changed

+18
-34
lines changed

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,15 @@ public static IntPtr ReAllocHGlobal(IntPtr pv, IntPtr cb)
8888
{
8989
nuint cbNative = (nuint)(nint)cb;
9090

91-
// Match Windows behavior by always allocating at least one byte and only when the original pointer is non-zero
92-
IntPtr pNewMem = (pv != IntPtr.Zero) ? Interop.Sys.MemReAlloc(pv, (cbNative != 0) ? cbNative : 1) : IntPtr.Zero;
91+
if (cbNative == 0)
92+
{
93+
// ReAllocHGlobal never returns null, even for 0 size (different from standard C/C++ realloc)
94+
95+
// Avoid undefined realloc behavior by always allocating at least one byte
96+
cbNative = 1;
97+
}
98+
99+
IntPtr pNewMem = Interop.Sys.MemReAlloc(pv, cbNative);
93100
if (pNewMem == IntPtr.Zero)
94101
{
95102
throw new OutOfMemoryException();

src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Windows.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,13 @@ public static void FreeHGlobal(IntPtr hglobal)
147147

148148
public static IntPtr ReAllocHGlobal(IntPtr pv, IntPtr cb)
149149
{
150+
if (pv == IntPtr.Zero)
151+
{
152+
// LocalReAlloc fails for pv == IntPtr.Zero. Call AllocHGlobal instead for better fidelity
153+
// with standard C/C++ realloc behavior.
154+
return AllocHGlobal(cb);
155+
}
156+
150157
IntPtr pNewMem = Interop.Kernel32.LocalReAlloc(pv, (nuint)(nint)cb, Interop.Kernel32.LMEM_MOVEABLE);
151158
if (pNewMem == IntPtr.Zero)
152159
{

src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/ReAllocCoTaskMemTests.cs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ public void ReAllocCoTaskMem_Invoke_DataCopied()
4343
[InlineData(1)]
4444
[InlineData(100)]
4545
[Theory]
46-
[SkipOnMono("Behavior differences on Mono")]
4746
public void ReAllocCoTaskMem_PositiveSize(int size)
4847
{
4948
IntPtr p = Marshal.ReAllocCoTaskMem(IntPtr.Zero, size);
@@ -53,22 +52,11 @@ public void ReAllocCoTaskMem_PositiveSize(int size)
5352
Assert.NotEqual(IntPtr.Zero, p1);
5453

5554
IntPtr p2 = Marshal.ReAllocCoTaskMem(p1, 0);
56-
57-
// TODO: Behavior differs between platforms currently
58-
if (PlatformDetection.IsWindows)
59-
{
60-
Assert.Equal(IntPtr.Zero, p2);
61-
}
62-
else
63-
{
64-
Assert.NotEqual(IntPtr.Zero, p2);
65-
Marshal.FreeCoTaskMem(p2);
66-
}
55+
Assert.Equal(IntPtr.Zero, p2);
6756
}
6857

6958
[Fact]
7059
[OuterLoop]
71-
[SkipOnMono("Behavior differences on Mono")]
7260
public void ReAllocCoTaskMem_NegativeSize_ThrowsOutOfMemoryException()
7361
{
7462
// -1 is treated as (uint)-1 by ReAllocCoTaskMem. The allocation may succeed on 64-bit machines.

src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/ReAllocHGlobalTests.cs

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,9 @@ public void ReAllocHGlobal_Invoke_DataCopied()
4444
[InlineData(1)]
4545
[InlineData(100)]
4646
[Theory]
47-
[SkipOnMono("Behavior differences on Mono")]
4847
public void ReAllocHGlobal_PositiveSize(int size)
4948
{
50-
IntPtr p;
51-
// TODO: Behavior differs between platforms currently
52-
if (PlatformDetection.IsWindows)
53-
{
54-
p = Marshal.AllocHGlobal(size);
55-
}
56-
else
57-
{
58-
p = Marshal.ReAllocHGlobal(IntPtr.Zero, (IntPtr)size);
59-
}
49+
IntPtr p = Marshal.ReAllocHGlobal(IntPtr.Zero, (IntPtr)size);
6050
Assert.NotEqual(IntPtr.Zero, p);
6151

6252
IntPtr p1 = Marshal.ReAllocHGlobal(p, (IntPtr)(size + 1));
@@ -70,16 +60,8 @@ public void ReAllocHGlobal_PositiveSize(int size)
7060
}
7161

7262
[Fact]
73-
[SkipOnMono("Behavior differences on Mono")]
7463
public void ReAllocHGlobal_NegativeSize_ThrowsOutOfMemoryException()
7564
{
76-
// TODO: Behavior differs between platforms currently
77-
if (PlatformDetection.IsWindows)
78-
{
79-
// ReAllocHGlobal always throws when the original pointer is null (different from standard C/C++ realloc)
80-
Assert.Throws<OutOfMemoryException>(() => Marshal.ReAllocHGlobal(IntPtr.Zero, IntPtr.Zero));
81-
Assert.Throws<OutOfMemoryException>(() => Marshal.ReAllocHGlobal(IntPtr.Zero, (IntPtr)1));
82-
}
8365
Assert.Throws<OutOfMemoryException>(() => Marshal.ReAllocHGlobal(IntPtr.Zero, (IntPtr)(-1)));
8466

8567
IntPtr p = Marshal.AllocHGlobal((IntPtr)1);

0 commit comments

Comments
 (0)