Export (0) Print
Expand All

Call GC.KeepAlive when using native resources

TypeName

CallGCKeepAliveWhenUsingNativeResources

CheckId

CA2115

Category

Microsoft.Security

Breaking Change

NonBreaking

A method declared in a type with a finalizer references a System.IntPtr or System.UIntPtr field, but does not call System.GC.KeepAlive(System.Object).

Garbage collection finalizes an object if there are no more references to it in managed code. Unmanaged references to objects do not prevent garbage collection. This rule detects errors that might occur because an unmanaged resource is being finalized while it is still being used in unmanaged code.

This rule assumes that IntPtr and UIntPtr fields store pointers to unmanaged resources. Because the purpose of a finalizer is to free unmanaged resources, the rule assumes that the finalizer will free the unmanaged resource pointed to by the pointer fields. This rule also assumes that the method is referencing the pointer field to pass the unmanaged resource to unmanaged code.

To fix a violation of this rule, add a call to KeepAlive to the method, passing the current instance (this in C# and C++) as the argument. Position the call after the last line of code where the object must be protected from garbage collection. Immediately after the call to KeepAlive, the object is again considered ready for garbage collection assuming that there are no managed references to it.

This rule makes certain assumptions that can lead to false positives. You can safely exclude a warning from this rule if:

  • The finalizer does not free the contents of the IntPtr or UIntPtr field referenced by the method.

  • The method does not pass the IntPtr or UIntPtr field to unmanaged code.

Carefully review other messages before excluding them. This rule detects errors that are difficult to reproduce and debug.

In this example, BadMethod violates the rule. GoodMethod contains the corrected code.

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 ...
      }
      
   }

}

Community Additions

ADD
Show:
© 2014 Microsoft