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


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

TypeName

CallGCKeepAliveWhenUsingNativeResources

CheckId

CA2115

Категория

Microsoft.Security

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

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

Причина

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

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

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

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

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

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

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

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

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

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

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

Пример

В данном пример метод 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