为什么我需要在“DangerousGetHandle”周围使用“DangerousAddRef”/“DangerousRelease”?

问题描述 投票:0回答:1

我一直在研究

Microsoft.Windows.CsWin32
NuGet 包,并将其生成的 P/Invoke 代码与我手写的代码进行比较。在某些情况下,它会使用
SafeHandle.DangerousAddRef
/
SafeHandle.DangerousRelease
,而我不会使用。我试图理解为什么,但没有想出任何办法。

这是 Win32

SetInformationJobObject
函数的示例:

[DllImport("KERNEL32.dll", ExactSpelling = true, SetLastError = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
[SupportedOSPlatform("windows5.1.2600")]
internal static extern unsafe winmdroot.Foundation.BOOL SetInformationJobObject(winmdroot.Foundation.HANDLE hJob, winmdroot.System.JobObjects.JOBOBJECTINFOCLASS JobObjectInformationClass, void* lpJobObjectInformation, uint cbJobObjectInformationLength);

/// <inheritdoc cref="AssignProcessToJobObject(winmdroot.Foundation.HANDLE, winmdroot.Foundation.HANDLE)"/>
[SupportedOSPlatform("windows5.1.2600")]
internal static unsafe winmdroot.Foundation.BOOL AssignProcessToJobObject(SafeHandle hJob, SafeHandle hProcess)
{
    bool hJobAddRef = false;
    bool hProcessAddRef = false;
    try
    {
        winmdroot.Foundation.HANDLE hJobLocal;
        if (hJob is object)
        {
            hJob.DangerousAddRef(ref hJobAddRef);
            hJobLocal = (winmdroot.Foundation.HANDLE)hJob.DangerousGetHandle();  // <-- THIS
        }
        else
            throw new ArgumentNullException(nameof(hJob));
        winmdroot.Foundation.HANDLE hProcessLocal;
        if (hProcess is object)
        {
            hProcess.DangerousAddRef(ref hProcessAddRef);
            hProcessLocal = (winmdroot.Foundation.HANDLE)hProcess.DangerousGetHandle();
        }
        else
            throw new ArgumentNullException(nameof(hProcess));
        winmdroot.Foundation.BOOL __result = PInvoke.AssignProcessToJobObject(hJobLocal, hProcessLocal); // calls the `extern` overload
        return __result;
    }
    finally
    {
        if (hJobAddRef)
            hJob.DangerousRelease();
        if (hProcessAddRef)
            hProcess.DangerousRelease();
    }
}

我期望第二个函数是这样的:

[DllImport("KERNEL32.dll", ExactSpelling = true, SetLastError = true)]
[SupportedOSPlatform("windows5.1.2600")]
internal static unsafe winmdroot.Foundation.BOOL AssignProcessToJobObject(SafeHandle hJob, SafeHandle hProcess)
{
    var localJob = (winmdroot.Foundation.HANDLE)hJob.DangerousGetHandle();
    var localProcess = (winmdroot.Foundation.HANDLE)hProcess.DangerousGetHandle();
    return (winmdroot.Foundation.BOOL)PInvoke.AssignProcessToJobObject(localJob, localProcess);
}

它似乎正在制作手柄的防御性副本,但我不知道这有什么帮助。即使

SafeHandle
持有的句柄发生变化(据我所知,它不应该发生变化),我们仍然会将 some 句柄传递给
extern
重载。

我尝试检查源生成器的代码以获取提示,并发现添加了调用的提交,但这并没有告诉我。我假设它是基于封送拆收器使用

SafeHandle
所做的事情。

关于为什么我们需要在这里增加引用计数有什么想法吗?

c# pinvoke
1个回答
0
投票

来自官方文档:

SafeHandle.DangerousGetHandle

使用 DangerousGetHandle 方法可能会带来安全风险,因为: 如果句柄已被标记为无效

SetHandleAsInvalid
DangerousGetHandle
仍然返回原始的,可能已经过时 处理值。返回的句柄也可以随时回收。 充其量,这意味着手柄可能会突然停止工作。最坏的情况是, 如果句柄或句柄代表的资源被公开 不受信任的代码,这可能会导致对 重复使用或返回的句柄。例如,不受信任的调用者可以查询 句柄上的数据刚刚返回并接收信息 完全不相关的资源。

[强调我的:] 参见

DangerousAddRef
DangerousRelease
方法以获取有关使用的更多信息
DangerousGetHandle
安全方法。

SafeHandle.DangerousAddRef

DangerousAddRef 方法可防止公共语言运行时回收句柄使用的内存(当运行时调用 ReleaseHandle 方法时会发生这种情况)。您可以使用此方法手动增加 SafeHandle 实例上的引用计数。 [...].

所以这似乎是为了确保句柄在使用时不会失效。

© www.soinside.com 2019 - 2024. All rights reserved.