Поделиться через


CA2115: вызывайте GC.KeepAlive при использовании собственных ресурсов

TypeName

CallGCKeepAliveWhenUsingNativeResources

CheckId

CA2115

Категория

Microsoft.Security

Критическое изменение

Не критическое

Причина

Метод, объявленный в типе, содержащем метод завершения, ссылается на поле IntPtr или UIntPtr, однако не вызывает метод GC.KeepAlive.

Описание правила

Сборка мусора завершает объект в том случае, если на него больше нет ссылок в управляемом коде.Ссылки на объект из машинного кода не препятствуют сборке мусора.Данное правило обнаруживает ошибки, которые могут возникать из-за завершения неуправляемых ресурсов, по-прежнему используемых в машинном коде.

Данное правило предполагает, что в полях IntPtr и UIntPtr хранятся указатели на неуправляемые ресурсы.Поскольку назначением метода завершения является освобождение неуправляемых ресурсов, правило предполагает, что метод завершения освободит неуправляемые ресурсы, на которые ссылаются указатели, содержащиеся в полях.Это правило также предполагает, что метод ссылается на поле указателя для передачи неуправляемого ресурса в машинный код.

Устранение нарушений

Чтобы устранить нарушение данного правила, добавьте вызов KeepAlive в метод, передающий в качестве аргумента текущий экземпляр (this в C# и C++).Поместите этот вызов после последней строки кода, в котором объект должен быть защищен от сборки мусора.Непосредственно после вызова KeepAlive объект снова считается готовым для сборки мусора при условии, что на него нет ссылок из управляемого кода.

Отключение предупреждений

В данном правиле используется несколько предположений, которые могут привести к ложным положительным результатам.Отключение предупреждений для этого правила безопасно, если выполняются следующие условия.

  • Метод завершения не освобождает содержимое поля IntPtr или UIntPtr, на которое ссылается метод.

  • Метод не передает поле IntPtr или UIntPtr в машинный код.

Прежде чем отключать другие сообщения, тщательно изучите их.Правило обнаруживает ошибки, воспроизведение и отладка которых крайне затруднительна.

Пример

В следующем примере BadMethod не включает вызов GC.KeepAlive и поэтому не нарушает правило.Метод 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 ...
      }

   }

}

См. также

Ссылки

GC.KeepAlive

IntPtr

Object.Finalize

UIntPtr

Другие ресурсы

Implementing Finalize and Dispose to Clean Up Unmanaged Resources