Share via


CA2115: Call GC.KeepAlive when using native resources

Item Value
RuleId 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.

Note

This rule has been deprecated. For more information, see Deprecated rules.

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