Skip to content

Commit a3a7e0d

Browse files
authored
More tests for Marshal.Realloc{HGlobal|CoTaskMem} (#41910)
- The corner case behavior of Marshal.Realloc method is non-standard and differs between the two realloc methods. Capture the current behavior in tests. - Add temporary workarounds for Windows vs. Unix differences - Disable the tests on Mono for now
1 parent 228acfd commit a3a7e0d

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

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

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,61 @@ public void ReAllocCoTaskMem_Invoke_DataCopied()
3838
Marshal.FreeCoTaskMem(p2);
3939
}
4040
}
41+
42+
[InlineData(0)]
43+
[InlineData(1)]
44+
[InlineData(100)]
45+
[Theory]
46+
[SkipOnMono("Behavior differences on Mono")]
47+
public void ReAllocCoTaskMem_PositiveSize(int size)
48+
{
49+
IntPtr p = Marshal.ReAllocCoTaskMem(IntPtr.Zero, size);
50+
Assert.NotEqual(IntPtr.Zero, p);
51+
52+
IntPtr p1 = Marshal.ReAllocCoTaskMem(p, size + 1);
53+
Assert.NotEqual(IntPtr.Zero, p1);
54+
55+
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+
}
67+
}
68+
69+
[Fact]
70+
[OuterLoop]
71+
[SkipOnMono("Behavior differences on Mono")]
72+
public void ReAllocCoTaskMem_NegativeSize_ThrowsOutOfMemoryException()
73+
{
74+
// -1 is treated as (uint)-1 by ReAllocCoTaskMem. The allocation may succeed on 64-bit machines.
75+
76+
try
77+
{
78+
IntPtr p1 = Marshal.ReAllocCoTaskMem(IntPtr.Zero, -1);
79+
Assert.NotEqual(IntPtr.Zero, p1);
80+
Marshal.FreeCoTaskMem(p1);
81+
}
82+
catch (OutOfMemoryException)
83+
{
84+
}
85+
86+
IntPtr p2 = Marshal.AllocCoTaskMem(1);
87+
try
88+
{
89+
p2 = Marshal.ReAllocCoTaskMem(p2, -1);
90+
Assert.NotEqual(IntPtr.Zero, p2);
91+
}
92+
catch (OutOfMemoryException)
93+
{
94+
}
95+
Marshal.FreeCoTaskMem(p2);
96+
}
4197
}
4298
}

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using Microsoft.Win32.SafeHandles;
45
using Xunit;
56

67
namespace System.Runtime.InteropServices.Tests
@@ -38,5 +39,52 @@ public void ReAllocHGlobal_Invoke_DataCopied()
3839
Marshal.FreeHGlobal(p2);
3940
}
4041
}
42+
43+
[InlineData(0)]
44+
[InlineData(1)]
45+
[InlineData(100)]
46+
[Theory]
47+
[SkipOnMono("Behavior differences on Mono")]
48+
public void ReAllocHGlobal_PositiveSize(int size)
49+
{
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+
}
60+
Assert.NotEqual(IntPtr.Zero, p);
61+
62+
IntPtr p1 = Marshal.ReAllocHGlobal(p, (IntPtr)(size + 1));
63+
Assert.NotEqual(IntPtr.Zero, p1);
64+
65+
// ReAllocHGlobal never returns null, even for 0 size (different from standard C/C++ realloc)
66+
IntPtr p2 = Marshal.ReAllocHGlobal(p1, IntPtr.Zero);
67+
Assert.NotEqual(IntPtr.Zero, p2);
68+
69+
Marshal.FreeHGlobal(p2);
70+
}
71+
72+
[Fact]
73+
[SkipOnMono("Behavior differences on Mono")]
74+
public void ReAllocHGlobal_NegativeSize_ThrowsOutOfMemoryException()
75+
{
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+
}
83+
Assert.Throws<OutOfMemoryException>(() => Marshal.ReAllocHGlobal(IntPtr.Zero, (IntPtr)(-1)));
84+
85+
IntPtr p = Marshal.AllocHGlobal((IntPtr)1);
86+
Assert.Throws<OutOfMemoryException>(() => Marshal.ReAllocHGlobal(p, (IntPtr)(-1)));
87+
Marshal.FreeHGlobal(p);
88+
}
4189
}
4290
}

0 commit comments

Comments
 (0)