CA2115: Call GC.KeepAlive when using native resources

Note

This article applies to Visual Studio 2015. If you're looking for the latest Visual Studio documentation, use the version selector at the top left. We recommend upgrading to Visual Studio 2019. Download it here

Item Value
TypeName CallGCKeepAliveWhenUsingNativeResources
CheckId CA2115
Category Microsoft.Security
Breaking Change Non Breaking

Cause

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

Rule Description

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.

How to Fix Violations

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.

When to Suppress Warnings

This rule makes some assumptions that can lead to false positives. You can safely suppress 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.

Example

In the following example, BadMethod does not include a call to GC.KeepAlive and therefore violates the rule. GoodMethod contains the corrected code.

Note

This example is pseudo-code Although the code compiles and runs, the warning is not fired because an unmanaged resource is not created or freed.

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

}

See Also

System.GC.KeepAlive System.IntPtr System.Object.Finalize System.UIntPtr Dispose Pattern