CA2115:使用本机资源时调用 GC.KeepAlive

类型名

CallGCKeepAliveWhenUsingNativeResources

CheckId

CA2115

类别

Microsoft.Security

是否重大更改

原因

在具有终结器的类型中声明的某方法引用 System.IntPtrSystem.UIntPtr 字段,但没有调用 GC.KeepAlive

规则说明

如果托管代码中没有对一个对象的其他引用,则垃圾回收将终止该对象。 对对象的非托管引用不会妨碍垃圾回收。 该规则检测由于在非托管代码仍在使用非托管资源时终止该非托管资源而可能发生的错误。

该规则假定 IntPtrUIntPtr 字段存储指向非托管资源的指针。 因为终结器用于释放非托管资源,所以该规则假定终结器将释放指针字段所指向的非托管资源。 该规则还假定方法正在引用指针字段以便将非托管资源传递给非托管代码。

如何解决冲突

要修复与该规则的冲突,请向该方法添加对 KeepAlive 的调用,将当前实例(在 C# 和 C++ 中为 this)作为参数传递。 在需要保护对象不被垃圾回收的代码中,将该调用放在代码的最后一行之后。 紧接对 KeepAlive 的调用之后,在假定没有对该对象的托管引用的情况下,再次认为可对该对象进行垃圾回收。

何时禁止显示警告

该规则做出可能导致误报的某些假设。 如果下列条件成立,即可以安全地禁止显示此规则发出的警告:

  • 终结器不会释放该方法引用的 IntPtrUIntPtr 字段的内容。

  • 该方法不会将 IntPtrUIntPtr 字段传递给非托管代码。

请在排除其他消息前认真检查这些消息。 该规则检测难以重现和调试的错误。

示例

在此示例中,BadMethod 与规则冲突。 GoodMethod 包含更正的代码。

using System;

namespace SecurityRulesLibrary
{
   class IntPtrFieldsAndFinalizeRequireGCKeepAlive
   {
      private IntPtr unmanagedResource;

      IntPtrFieldsAndFinalizeRequireGCKeepAlive()
      {
         GetUnmanagedResource (unmanagedResource);
      }

      // The finalizer frees the unmanaged resource.
      ~IntPtrFieldsAndFinalizeRequireGCKeepAlive()
      {
         FreeUnmanagedResource (unmanagedResource);
      }

      // Violates rule:CallGCKeepAliveWhenUsingNativeResources. 
      void BadMethod()
      {
         // Call some unmanaged code.
         CallUnmanagedCode(unmanagedResource);
      }

      // Satisfies the rule.
      void GoodMethod()
      {
         // Call some unmanaged code.
         CallUnmanagedCode(unmanagedResource);
         GC.KeepAlive(this);
      }

      // Methods that would typically make calls to unmanaged code.
      void GetUnmanagedResource(IntPtr p)
      {
        // Allocate the resource ...
      }
      void FreeUnmanagedResource(IntPtr p)
      {
        // Free the resource and set the pointer to null ...
      }
      void CallUnmanagedCode(IntPtr p)
      {
        // Use the resource in unmanaged code ...
      }

   }

}

请参见

参考

实现 Finalize 和 Dispose 以清理非托管资源

GC.KeepAlive

System.IntPtr

Object.Finalize

System.UIntPtr