CA1404 - 尽管语句前面有返回子句CA2000 - 尽管没有进一步的参考用法

时间:2013-01-22 10:47:44

标签: c# code-analysis

我想了解为什么我的代码中会出现两个CA警告:

CA2000 在丢失范围之前处置对象在方法'ImpersonateValidUser(string,string,string,LogOnType,LogOnProvider,ImpersonationLevel)'中,在对象'tempWindowsIdentity'上调用System.IDisposable.Dispose对它的所有引用都超出了范围。

CA1404 在P / Invoke方法'ImpersonateValidUser(字符串,字符串,字符串,LogOnType,LogOnProvider,ImpersonationLevel)'之后立即调用GetLastError,调用GetLastWin32Error,但前一次调用'IDisposable.Dispose ()'不是P / Invoke语句。将调用移至GetLastWin32Error,以便它立即跟随相关的平台调用调用。

下面是简化的代码示例,其中的行在警告外观的位置完全注释:

private static void Impersonate(string userName, string domain, string password, LogOnType logonType, LogOnProvider logonProvider, ImpersonationLevel impersonationLevel)
{
    var token = IntPtr.Zero;
    var tokenDuplicate = IntPtr.Zero;
    if (NativeMethods.RevertToSelf())
    {
        if (NativeMethods.LogonUser(userName, domain, password, (int)logonType, (int)logonProvider, ref token) != 0)
        {
            if (NativeMethods.DuplicateToken(token, (int)impersonationLevel, ref tokenDuplicate) != 0)
            {
                /* CA2000 */ using (var tempWindowsIdentity = new WindowsIdentity(tokenDuplicate))
                {
                    _impersonationContext = tempWindowsIdentity.Impersonate();
                    return;
                }
            }
        }
    }
    /* CA1404 */ var e = Marshal.GetLastWin32Error();
    throw new Win32Exception(e);
}

CA2000 - tempWindowsIdentity语句完成后未使用对象using(),为什么会出现此警告?

CA1404 - 始终在本机方法之后调用Marshal.GetLastWin32Error()。即使在先前调用了using()语句的情况下,也会出现return子句,因此不会调用Marshal.GetLastWin32Error(),为什么会出现此警告?

3 个答案:

答案 0 :(得分:0)

此代码应该修复那些CA警告......不是很优雅......但代码分析永远不会产生优雅的代码。

private static void Impersonate(string userName, string domain, string password, LogOnType logonType, LogOnProvider logonProvider, ImpersonationLevel impersonationLevel)
{
    if (!NativeMethods.RevertToSelf())
        throw new Win32Exception(Marshal.GetLastWin32Error());

    IntPtr token = IntPtr.Zero;

    if (NativeMethods.LogonUser(userName, domain, password, (int)logonType, (int)logonProvider, ref token) == 0)
        throw new Win32Exception(Marshal.GetLastWin32Error());

    IntPtr tokenDuplicate = IntPtr.Zero;

    if (NativeMethods.DuplicateToken(token, (int)impersonationLevel, ref tokenDuplicate) == 0)
        throw new Win32Exception(Marshal.GetLastWin32Error());

WindowsIdentity tempWindowsIdentity;

    try
    {
        tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
        _impersonationContext = tempWindowsIdentity.Impersonate();
    }
    finally
    {
        if (tempPort != null)
        {
            tempWindowsIdentity.Dispose();
            tempWindowsIdentity = null;
        }
    }
}

对于CA1404有什么问题,如果你没有立即捕获它,那么错误的API调用引发的错误代码可能同时被来自其他托管类库方法的内部调用所覆盖。 在CA2000中,创建了方法中的WindowsIdentity,但在对象的所有引用都超出范围之前,不会释放对象;这样做不允许在故障点引发异常。

答案 1 :(得分:0)

我相信CA2000会在您违反规则的以下部分时发生,这意味着您正在using语句中创建一次性对象;

  

返回一次性物体需要构造物体   在使用块之外的try / finally块中。

同样发生CA1404,因为您在本机调用后没有立即调用Marshal.GetLastWin32Error();。尝试在每个Marshal.GetLastWin32Error();语句中调用if作为代码中的第一项。

答案 2 :(得分:-1)

我们通过以下方式解决了CA1404问题。原因是"!= 0"是LogonUser()或DuplicateToken()之后的立即调用。

private static void Impersonate(string userName, string domain, string password, LogOnType logonType, LogOnProvider logonProvider, ImpersonationLevel impersonationLevel)
{
    var token = IntPtr.Zero;
    var tokenDuplicate = IntPtr.Zero;
    if (NativeMethods.RevertToSelf())
    {
        var logonUserSuccessful = NativeMethods.LogonUser(userName, domain, password, (int) logonType, (int) logonProvider, ref token);
        var e = Marshal.GetLastWin32Error();  // call before comparison against 0 to avoid CA1404
        if (logonUserSuccessful != 0)
        {
            var duplicateTokenSuccessful = NativeMethods.DuplicateToken(token, (int) impersonationLevel, ref tokenDuplicate);
            e = Marshal.GetLastWin32Error();  // call before comparison against 0 to avoid CA1404
            if (duplicateTokenSuccessful != 0)
            {
                /* CA2000 */
                using (var tempWindowsIdentity = new WindowsIdentity(tokenDuplicate))
                {
                    _impersonationContext = tempWindowsIdentity.Impersonate();
                    return;
                }
            }
        }
    }
    throw new Win32Exception(e);
}