Skip to content

Commit d0d7154

Browse files
authored
Refactor Interop.LocalAlloc (#82450)
* Refactor `Interop.LocalAlloc`
1 parent 2323fc8 commit d0d7154

File tree

16 files changed

+117
-66
lines changed

16 files changed

+117
-66
lines changed

Diff for: src/libraries/Common/src/Interop/Windows/Advapi32/Interop.ConvertStringSidToSid.cs

+4-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ internal static partial class Interop
88
{
99
internal static partial class Advapi32
1010
{
11+
// https://learn.microsoft.com/windows/win32/api/sddl/nf-sddl-convertstringsidtosidw
1112
[LibraryImport(Interop.Libraries.Advapi32, EntryPoint = "ConvertStringSidToSidW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
12-
internal static partial BOOL ConvertStringSidToSid(
13-
string stringSid,
14-
out IntPtr ByteArray);
13+
internal static unsafe partial BOOL ConvertStringSidToSid(
14+
string StringSid,
15+
out void* Sid);
1516
}
1617
}

Diff for: src/libraries/Common/src/Interop/Windows/Kernel32/Interop.LocalAlloc.cs

+10-8
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@ internal static partial class Interop
88
{
99
internal static partial class Kernel32
1010
{
11-
internal const uint LMEM_FIXED = 0x0000;
12-
internal const uint LMEM_MOVEABLE = 0x0002;
13-
internal const uint LMEM_ZEROINIT = 0x0040;
11+
private const uint LMEM_FIXED = 0x000;
12+
private const uint LMEM_ZEROINIT = 0x0040;
13+
private const uint LPTR = LMEM_FIXED | LMEM_ZEROINIT;
1414

15+
// https://learn.microsoft.com/windows/win32/api/winbase/nf-winbase-localalloc
1516
[LibraryImport(Libraries.Kernel32)]
16-
internal static partial IntPtr LocalAlloc(uint uFlags, nuint uBytes);
17+
// [return: NativeTypeName("HLOCAL")]
18+
private static partial nint LocalAlloc(uint uFlags, nuint uBytes);
1719

18-
[LibraryImport(Libraries.Kernel32)]
19-
internal static partial IntPtr LocalReAlloc(IntPtr hMem, nuint uBytes, uint uFlags);
20+
internal static unsafe void* LocalAlloc(nuint byteCount) =>
21+
(void*)LocalAlloc(LMEM_FIXED, byteCount);
2022

21-
[LibraryImport(Libraries.Kernel32)]
22-
internal static partial IntPtr LocalFree(IntPtr hMem);
23+
internal static unsafe void* LocalAllocZeroed(nuint byteCount) =>
24+
(void*)LocalAlloc(LPTR, byteCount);
2325
}
2426
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Runtime.InteropServices;
5+
6+
internal static partial class Interop
7+
{
8+
internal static partial class Kernel32
9+
{
10+
// https://learn.microsoft.com/windows/win32/api/winbase/nf-winbase-localfree
11+
[LibraryImport(Libraries.Kernel32)]
12+
// [return: NativeTypeName("HLOCAL")]
13+
private static partial nint LocalFree(
14+
// [NativeTypeName("HLOCAL")]
15+
nint hMem);
16+
17+
internal static unsafe void* LocalFree(void* ptr) => (void*)LocalFree((nint)ptr);
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Runtime.InteropServices;
5+
6+
internal static partial class Interop
7+
{
8+
internal static partial class Kernel32
9+
{
10+
internal const uint LMEM_MOVEABLE = 0x0002;
11+
12+
// https://learn.microsoft.com/windows/win32/api/winbase/nf-winbase-localrealloc
13+
[LibraryImport(Libraries.Kernel32)]
14+
// [return: NativeTypeName("HLOCAL")]
15+
private static partial nint LocalReAlloc(
16+
// [NativeTypeName("HLOCAL")]
17+
nint hMem,
18+
nuint uBytes,
19+
uint uFlags);
20+
21+
internal static unsafe void* LocalReAlloc(void* ptr, nuint byteCount) =>
22+
(void*)LocalReAlloc((nint)ptr, byteCount, LMEM_MOVEABLE);
23+
}
24+
}

Diff for: src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ System.Data.OleDb.OleDbTransaction</PackageDescription>
3838
Link="Common\Interop\Windows\Kernel32\Interop.GetCurrentProcessId.cs" />
3939
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.LocalAlloc.cs"
4040
Link="Common\Interop\Windows\Kernel32\Interop.LocalAlloc.cs" />
41+
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.LocalFree.cs"
42+
Link="Common\Interop\Windows\Kernel32\Interop.LocalFree.cs" />
4143
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.Semaphore.cs"
4244
Link="Common\Interop\Windows\Kernel32\Interop.Semaphore.cs" />
4345
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.WaitForSingleObject.cs"

Diff for: src/libraries/System.Data.OleDb/src/System/Data/ProviderBase/DbBuffer.cs

+5-11
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,17 @@ internal abstract class DbBuffer : SafeHandle
1414
{
1515
private readonly int _bufferLength;
1616

17-
private DbBuffer(int initialSize, bool zeroBuffer) : base(IntPtr.Zero, true)
17+
protected unsafe DbBuffer(int initialSize) : base(IntPtr.Zero, true)
1818
{
1919
if (0 < initialSize)
2020
{
21-
uint flags = ((zeroBuffer) ? Interop.Kernel32.LMEM_ZEROINIT : Interop.Kernel32.LMEM_FIXED);
22-
2321
_bufferLength = initialSize;
2422
RuntimeHelpers.PrepareConstrainedRegions();
2523
try
2624
{ }
2725
finally
2826
{
29-
base.handle = Interop.Kernel32.LocalAlloc(flags, (nuint)initialSize);
27+
base.handle = (IntPtr)Interop.Kernel32.LocalAllocZeroed((uint)initialSize);
3028
}
3129
if (IntPtr.Zero == base.handle)
3230
{
@@ -35,10 +33,6 @@ private DbBuffer(int initialSize, bool zeroBuffer) : base(IntPtr.Zero, true)
3533
}
3634
}
3735

38-
protected DbBuffer(int initialSize) : this(initialSize, true)
39-
{
40-
}
41-
4236
protected DbBuffer(IntPtr invalidHandleValue, bool ownsHandle) : base(invalidHandleValue, ownsHandle)
4337
{
4438
}
@@ -347,12 +341,12 @@ internal unsafe float ReadSingle(int offset)
347341
return BitConverter.Int32BitsToSingle(value);
348342
}
349343

350-
protected override bool ReleaseHandle()
344+
protected override unsafe bool ReleaseHandle()
351345
{
352346
// NOTE: The SafeHandle class guarantees this will be called exactly once.
353-
IntPtr ptr = base.handle;
347+
void* ptr = (void*)base.handle;
354348
base.handle = IntPtr.Zero;
355-
if (IntPtr.Zero != ptr)
349+
if (ptr is not null)
356350
{
357351
Interop.Kernel32.LocalFree(ptr);
358352
}

Diff for: src/libraries/System.DirectoryServices.AccountManagement/src/System.DirectoryServices.AccountManagement.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@
170170
Link="Common\Interop\Windows\Kernel32\Interop.GetCurrentThreadId.cs" />
171171
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.LocalAlloc.cs"
172172
Link="Common\Interop\Windows\Kernel32\Interop.LocalAlloc.cs" />
173+
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.LocalFree.cs"
174+
Link="Common\Interop\Windows\Kernel32\Interop.LocalFree.cs" />
173175
<Compile Include="$(CommonPath)Interop\Windows\Logoncli\Interop.DsGetDcName.cs"
174176
Link="Common\Interop\Windows\Logoncli\Interop.DsGetDcName.cs" />
175177
<Compile Include="$(CommonPath)Interop\Windows\Netutils\Interop.NetApiBufferFree.cs"

Diff for: src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/AD/ADStoreCtx.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1530,9 +1530,9 @@ internal override ResultSet GetGroupsMemberOf(Principal foreignPrincipal, StoreC
15301530
}
15311531
}
15321532

1533-
private string GetGroupDnFromGroupID(byte[] userSid, int primaryGroupId)
1533+
private unsafe string GetGroupDnFromGroupID(byte[] userSid, int primaryGroupId)
15341534
{
1535-
IntPtr pGroupSid = IntPtr.Zero;
1535+
void* pGroupSid = null;
15361536
byte[] groupSid = null;
15371537

15381538
// This function is based on the technique in KB article 297951.
@@ -1554,14 +1554,14 @@ private string GetGroupDnFromGroupID(byte[] userSid, int primaryGroupId)
15541554
if (Interop.Advapi32.ConvertStringSidToSid(sddlSid, out pGroupSid) != Interop.BOOL.FALSE)
15551555
{
15561556
// Now we convert the native SID to a byte[] SID
1557-
groupSid = Utils.ConvertNativeSidToByteArray(pGroupSid);
1557+
groupSid = Utils.ConvertNativeSidToByteArray((IntPtr)pGroupSid);
15581558
}
15591559
}
15601560
}
15611561
}
15621562
finally
15631563
{
1564-
if (pGroupSid != IntPtr.Zero)
1564+
if (pGroupSid is not null)
15651565
Interop.Kernel32.LocalFree(pGroupSid);
15661566
}
15671567

Diff for: src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/AD/ADStoreCtx_Query.cs

+6-6
Original file line numberDiff line numberDiff line change
@@ -491,19 +491,19 @@ protected static string IdentityClaimConverter(FilterBase filter, string suggest
491491

492492
// If useSidHistory == false, build a filter for objectSid.
493493
// If useSidHistory == true, build a filter for objectSid and sidHistory.
494-
protected static bool SecurityIdentityClaimConverterHelper(string urnValue, bool useSidHistory, StringBuilder filter, bool throwOnFail)
494+
protected static unsafe bool SecurityIdentityClaimConverterHelper(string urnValue, bool useSidHistory, StringBuilder filter, bool throwOnFail)
495495
{
496496
// String is in SDDL format. Translate it to ldap hex format
497497

498-
IntPtr pBytePtr = IntPtr.Zero;
498+
void* pSid = null;
499499
byte[] sidB = null;
500500

501501
try
502502
{
503-
if (Interop.Advapi32.ConvertStringSidToSid(urnValue, out pBytePtr) != Interop.BOOL.FALSE)
503+
if (Interop.Advapi32.ConvertStringSidToSid(urnValue, out pSid) != Interop.BOOL.FALSE)
504504
{
505505
// Now we convert the native SID to a byte[] SID
506-
sidB = Utils.ConvertNativeSidToByteArray(pBytePtr);
506+
sidB = Utils.ConvertNativeSidToByteArray((IntPtr)pSid);
507507
if (null == sidB)
508508
{
509509
if (throwOnFail)
@@ -522,8 +522,8 @@ protected static bool SecurityIdentityClaimConverterHelper(string urnValue, bool
522522
}
523523
finally
524524
{
525-
if (IntPtr.Zero != pBytePtr)
526-
Interop.Kernel32.LocalFree(pBytePtr);
525+
if (pSid is not null)
526+
Interop.Kernel32.LocalFree(pSid);
527527
}
528528

529529
StringBuilder stringizedBinarySid = new StringBuilder();

Diff for: src/libraries/System.DirectoryServices/src/System.DirectoryServices.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@ System.DirectoryServices.ActiveDirectory.DomainController</PackageDescription>
220220
Link="Common\Interop\Windows\Kernel32\Interop.LoadLibrary.cs" />
221221
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.LocalAlloc.cs"
222222
Link="Common\Interop\Windows\Kernel32\Interop.LocalAlloc.cs" />
223+
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.LocalFree.cs"
224+
Link="Common\Interop\Windows\Kernel32\Interop.LocalFree.cs" />
223225
<Compile Include="$(CommonPath)Interop\Windows\OleAut32\Interop.VariantClear.cs"
224226
Link="Common\Interop\Windows\OleAut32\Interop.VariantClear.cs" />
225227
<Compile Include="$(CommonPath)Interop\Windows\NtDll\Interop.NtStatus.cs"

Diff for: src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySite.cs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1298,25 +1298,25 @@ private unsafe void GetDomains()
12981298

12991299
Debug.Assert(handle != (IntPtr)0);
13001300

1301-
IntPtr info = (IntPtr)0;
1301+
void* pDomains = null;
13021302
// call DsReplicaSyncAllW
1303-
var dsListDomainsInSiteW = (delegate* unmanaged<IntPtr, char*, IntPtr*, int>)global::Interop.Kernel32.GetProcAddress(DirectoryContext.ADHandle, "DsListDomainsInSiteW");
1303+
var dsListDomainsInSiteW = (delegate* unmanaged<IntPtr, char*, void**, int>)global::Interop.Kernel32.GetProcAddress(DirectoryContext.ADHandle, "DsListDomainsInSiteW");
13041304
if (dsListDomainsInSiteW == null)
13051305
{
13061306
throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastPInvokeError());
13071307
}
13081308

13091309
fixed (char* distinguishedName = (string)PropertyManager.GetPropertyValue(context, cachedEntry, PropertyManager.DistinguishedName)!)
13101310
{
1311-
int result = dsListDomainsInSiteW(handle, distinguishedName, &info);
1311+
int result = dsListDomainsInSiteW(handle, distinguishedName, &pDomains);
13121312
if (result != 0)
13131313
throw ExceptionHelper.GetExceptionFromErrorCode(result, serverName);
13141314
}
13151315

13161316
try
13171317
{
13181318
DS_NAME_RESULT names = new DS_NAME_RESULT();
1319-
Marshal.PtrToStructure(info, names);
1319+
Marshal.PtrToStructure((IntPtr)pDomains, names);
13201320
int count = names.cItems;
13211321
IntPtr val = names.rItems;
13221322
if (count > 0)
@@ -1344,13 +1344,13 @@ private unsafe void GetDomains()
13441344
finally
13451345
{
13461346
// call DsFreeNameResultW
1347-
var dsFreeNameResultW = (delegate* unmanaged<IntPtr, void>)global::Interop.Kernel32.GetProcAddress(DirectoryContext.ADHandle, "DsFreeNameResultW");
1347+
var dsFreeNameResultW = (delegate* unmanaged<void*, void>)global::Interop.Kernel32.GetProcAddress(DirectoryContext.ADHandle, "DsFreeNameResultW");
13481348
if (dsFreeNameResultW == null)
13491349
{
13501350
throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastPInvokeError());
13511351
}
13521352

1353-
dsFreeNameResultW(info);
1353+
dsFreeNameResultW(pDomains);
13541354
}
13551355
}
13561356
}

Diff for: src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/DirectoryServer.cs

+7-7
Original file line numberDiff line numberDiff line change
@@ -626,14 +626,14 @@ internal bool SyncAllCallbackRoutine(IntPtr data, IntPtr update)
626626

627627
internal unsafe void SyncReplicaAllHelper(IntPtr handle, SyncReplicaFromAllServersCallback syncAllCallback, string partition, SyncFromAllServersOptions option, SyncUpdateCallback? callback, SafeLibraryHandle libHandle)
628628
{
629-
IntPtr errorInfo = (IntPtr)0;
629+
void* pErrors = null;
630630

631631
if (!Partitions.Contains(partition))
632632
throw new ArgumentException(SR.ServerNotAReplica, nameof(partition));
633633

634634
// we want to return the dn instead of DNS guid
635635
// call DsReplicaSyncAllW
636-
var dsReplicaSyncAllW = (delegate* unmanaged<IntPtr, char*, int, IntPtr, IntPtr, IntPtr*, int>)global::Interop.Kernel32.GetProcAddress(libHandle, "DsReplicaSyncAllW");
636+
var dsReplicaSyncAllW = (delegate* unmanaged<IntPtr, char*, int, IntPtr, IntPtr, void**, int>)global::Interop.Kernel32.GetProcAddress(libHandle, "DsReplicaSyncAllW");
637637
if (dsReplicaSyncAllW == null)
638638
{
639639
throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastPInvokeError());
@@ -643,16 +643,16 @@ internal unsafe void SyncReplicaAllHelper(IntPtr handle, SyncReplicaFromAllServe
643643
fixed (char* partitionPtr = partition)
644644
{
645645
IntPtr syncAllFunctionPointer = Marshal.GetFunctionPointerForDelegate(syncAllCallback);
646-
result = dsReplicaSyncAllW(handle, partitionPtr, (int)option | DS_REPSYNCALL_ID_SERVERS_BY_DN, syncAllFunctionPointer, (IntPtr)0, &errorInfo);
646+
result = dsReplicaSyncAllW(handle, partitionPtr, (int)option | DS_REPSYNCALL_ID_SERVERS_BY_DN, syncAllFunctionPointer, (IntPtr)0, &pErrors);
647647
GC.KeepAlive(syncAllCallback);
648648
}
649649

650650
try
651651
{
652652
// error happens during the synchronization
653-
if (errorInfo != (IntPtr)0)
653+
if (pErrors is not null)
654654
{
655-
SyncFromAllServersOperationException? e = ExceptionHelper.CreateSyncAllException(errorInfo, false);
655+
SyncFromAllServersOperationException? e = ExceptionHelper.CreateSyncAllException((IntPtr)pErrors, false);
656656
if (e == null)
657657
return;
658658
else
@@ -668,8 +668,8 @@ internal unsafe void SyncReplicaAllHelper(IntPtr handle, SyncReplicaFromAllServe
668668
finally
669669
{
670670
// release the memory
671-
if (errorInfo != (IntPtr)0)
672-
global::Interop.Kernel32.LocalFree(errorInfo);
671+
if (pErrors is not null)
672+
global::Interop.Kernel32.LocalFree(pErrors);
673673
}
674674
}
675675

Diff for: src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ForestTrustRelationshipInformation.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public ForestTrustDomainInfoCollection TrustedDomainInformation
7878
}
7979
}
8080

81-
public void Save()
81+
public unsafe void Save()
8282
{
8383
int count = 0;
8484
IntPtr records = (IntPtr)0;
@@ -181,14 +181,14 @@ public void Save()
181181
record.ForestTrustType = LSA_FOREST_TRUST_RECORD_TYPE.ForestTrustDomainInfo;
182182
ForestTrustDomainInformation tmp = _domainInfo[i];
183183
record.Time = tmp.time;
184-
IntPtr pSid = (IntPtr)0;
184+
void* pSid = null;
185185
global::Interop.BOOL result = global::Interop.Advapi32.ConvertStringSidToSid(tmp.DomainSid, out pSid);
186186
if (result == global::Interop.BOOL.FALSE)
187187
{
188188
throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastPInvokeError());
189189
}
190-
record.DomainInfo.sid = pSid;
191-
sidList.Add(pSid);
190+
record.DomainInfo.sid = (IntPtr)pSid;
191+
sidList.Add((IntPtr)pSid);
192192
record.DomainInfo.DNSNameBuffer = Marshal.StringToHGlobalUni(tmp.DnsName);
193193
ptrList.Add(record.DomainInfo.DNSNameBuffer);
194194
record.DomainInfo.DNSNameLength = (short)(tmp.DnsName == null ? 0 : tmp.DnsName.Length * 2); // sizeof(WCHAR)
@@ -289,7 +289,7 @@ public void Save()
289289

290290
for (int i = 0; i < sidList.Count; i++)
291291
{
292-
global::Interop.Kernel32.LocalFree((IntPtr)sidList[i]!);
292+
global::Interop.Kernel32.LocalFree((void*)(nint)sidList[i]!);
293293
}
294294

295295
if (records != (IntPtr)0)

Diff for: src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems

+6
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,12 @@
17691769
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.LocalAlloc.cs">
17701770
<Link>Common\Interop\Windows\Kernel32\Interop.LocalAlloc.cs</Link>
17711771
</Compile>
1772+
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.LocalFree.cs">
1773+
<Link>Common\Interop\Windows\Kernel32\Interop.LocalFree.cs</Link>
1774+
</Compile>
1775+
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.LocalReAlloc.cs">
1776+
<Link>Common\Interop\Windows\Kernel32\Interop.LocalReAlloc.cs</Link>
1777+
</Compile>
17721778
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.LockFile.cs">
17731779
<Link>Common\Interop\Windows\Kernel32\Interop.LockFile.cs</Link>
17741780
</Compile>

0 commit comments

Comments
 (0)