共用方式為


CA2115:使用原生資源時必須呼叫 GC.KeepAlive

型別名稱

CallGCKeepAliveWhenUsingNativeResources

CheckId

CA2115

分類

Microsoft.Security

中斷變更

不中斷

原因

在具有完成項之型別中所宣告的方法會參考 System.IntPtrSystem.UIntPtr 欄位,但是不會呼叫 GC.KeepAlive

規則描述

如果 Managed 程式碼中不再參考物件,則記憶體回收會完成物件。對物件的 Unmanaged 參考無法避免記憶體回收。此規則所偵測的錯誤,可能是因為在 Unmanaged 程式碼仍在使用 Unmanaged 資源時,就完成 Unmanaged 資源所致。

此規則假設 IntPtrUIntPtr 欄位會儲存 Unmanaged 資源的指標。因為完成項的用途是釋放 Unmanaged 資源,因此,此規則假設完成項會釋放指標欄位所指向的 Unmanaged 資源。此規則也假設方法正參考指標欄位,以將 Unmanaged 資源傳遞給 Unmanaged 程式碼。

如何修正違規

若要修正此規則的違規情形,請將對 KeepAlive 的呼叫加入至方法,傳遞目前的執行個體 (C# 和 C++ 中為 this) 做為引數。在必須防止物件進行記憶體回收之程式碼的最後一行之後放置此呼叫。在 KeepAlive 的呼叫之後,會立即假設物件沒有 Managed 參考,而將物件再次視為可以進行記憶體回收。

隱藏警告的時機

此規則的某些假設會導致誤報。在下列情況下,您可以放心地隱藏此規則的警告:

  • 完成項未釋放 IntPtr 的內容或方法所參考的 UIntPtr 欄位。

  • 方法未傳遞 IntPtrUIntPtr 欄位至 Unmanaged 程式碼。

請先仔細地檢視訊息,再將它排除。此規則所偵測的錯誤難以重現和偵錯。

範例

在下列範例中, BadMethod 不含呼叫 GC.KeepAlive 因此違反規則。GoodMethod 包含修正過的程式碼。

注意事項注意事項

這個範例是虛擬程式碼,雖然程式碼編譯並執行,因為 Unmanaged 資源不會建立或並未釋放,所以警告不會引發。

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

   }

}

請參閱

參考

Implementing Finalize and Dispose to Clean Up Unmanaged Resources

GC.KeepAlive

System.IntPtr

Object.Finalize

System.UIntPtr