Sdílet prostřednictvím


CA2020: Zabránění změnám chování způsobeným integrovanými operátory IntPtr/UIntPtr

Vlastnost Hodnota
ID pravidla CA2020
Název Zabránění změnám chování způsobeným integrovanými operátory IntPtr/UIntPtr
Kategorie Spolehlivost
Oprava způsobující chybu nebo chybu způsobující chybu Nenarušující
Povoleno ve výchozím nastavení v .NET 9 Jako návrh

Příčina

Toto pravidlo se aktivuje, když zjistí změnu chování mezi .NET 6 a .NET 7 zavedenými novými integrovanými operátory IntPtr a UIntPtr.

Popis pravidla

S numerickou funkcíIntPtr IntPtr a UIntPtr získali integrované operátory pro převody, unární operace a binární operace. Tyto operátory můžou vyvolat přetečení v rámci kontrolovaného kontextu nebo nemusí vyvolat nezaškrtnutý kontext v porovnání s předchozími uživatelem definovanými operátory v .NET 6 a starších verzích. K této změně chování může dojít při upgradu na .NET 7.

Seznam ovlivněných rozhraní API

Operátor Kontext V .NET 7 V .NET 6 a starších verzích Příklad
operator +(IntPtr, int) checked Vyvolá při přetečení Při přetečení se nehodí checked(intPtrVariable + 2);
– (IntPtr, int) checked Vyvolá při přetečení Při přetečení se nehodí checked(intPtrVariable - 2);
explicitní operátor IntPtr(long) unchecked Při přetečení se nehodí Může vyvolat 32bitové kontexty (IntPtr)longVariable;
explicitní operátor void*(IntPtr) checked vyvolá při přetečení Při přetečení se nehodí checked((void*)intPtrVariable);
explicitní operátor IntPtr(void*) checked vyvolá při přetečení Při přetečení se nehodí checked((IntPtr)voidPtrVariable);
explicitní operátor int(IntPtr) unchecked Při přetečení se nehodí Může vyvolat 64bitové kontexty (int)intPtrVariable;
operator +(UIntPtr, int) checked Vyvolá při přetečení Při přetečení se nehodí checked(uintPtrVariable + 2);
– operátor -(UIntPtr, int) checked Vyvolá při přetečení Při přetečení se nehodí checked(uintPtrVariable - 2);
explicitní operátor UIntPtr(ulong) unchecked Při přetečení se nehodí Může vyvolat 32bitové kontexty (UIntPtr)uLongVariable
explicitní operátor uint(UIntPtr) unchecked Při přetečení se nehodí Může vyvolat 64bitové kontexty (uint)uintPtrVariable

Jak opravit porušení

Prozkoumejte kód a zjistěte, jestli výraz s příznakem může způsobit změnu chování, a zvolte vhodný způsob, jak opravit diagnostiku z následujících možností:

Možnosti opravy:

  • Pokud výraz nezpůsobí změnu chování:
    • IntPtr Pokud se typ UIntPtr používá jako nativní int nebo uint, změňte typ na nint nebo nuint.
    • IntPtr Pokud se typ UIntPtr používá jako nativní ukazatel, změňte typ na odpovídající nativní typ ukazatele.
    • Pokud nemůžete změnit typ proměnné, potlačit upozornění.
  • Pokud by výraz mohl způsobit změnu chování, zabalte ho pomocí checked příkazu nebo unchecked zachovejte předchozí chování.

Příklad

Porušení:

using System;

public unsafe class IntPtrTest
{
    IntPtr intPtrVariable;
    long longVariable;

    void Test ()
    {
        checked
        {
            IntPtr result = intPtrVariable + 2; // Warns: Starting with .NET 7 the operator '+' will throw when overflowing in a checked context. Wrap the expression with an 'unchecked' statement to restore the .NET 6 behavior.

            result = intPtrVariable - 2; // Starting with .NET 7 the operator '-' will throw when overflowing in a checked context. Wrap the expression with an 'unchecked' statement to restore the .NET 6 behavior.

            void* voidPtrVariable = (void*)intPtrVariable; // Starting with .NET 7 the explicit conversion '(void*)IntPtr' will throw when overflowing in a checked context. Wrap the expression with an 'unchecked' statement to restore the .NET 6 behavior.

            result = (IntPtr)voidPtrVariable; // Starting with .NET 7 the explicit conversion '(IntPtr)void*' will throw when overflowing in a checked context. Wrap the expression with an 'unchecked' statement to restore the .NET 6 behavior.
        }

        intPtrVariable = (IntPtr)longVariable; // Starting with .NET 7 the explicit conversion '(IntPtr)Int64' will not throw when overflowing in an unchecked context. Wrap the expression with a 'checked' statement to restore the .NET 6 behavior.

        int a = (int)intPtrVariable; // Starting with .NET 7 the explicit conversion '(Int32)IntPtr' will not throw when overflowing in an unchecked context. Wrap the expression with a 'checked' statement to restore the .NET 6 behavior.
    }
}

Oprava:

  • Pokud výraz nezpůsobí změnu chování a IntPtr typ se UIntPtr použije jako nativní int nebo uint, změňte typ na nint nebo nuint.
using System;

public unsafe class IntPtrTest
{
    nint intPtrVariable; // type changed to nint
    long longVariable;

    void Test ()
    {
        checked
        {
            nint result = intPtrVariable + 2; // no warning

            result = intPtrVariable - 2;

            void* voidPtrVariable = (void*)intPtrVariable;

            result = (nint)voidPtrVariable;
        }

        intPtrVariable = (nint)longVariable;

        int a = (int)intPtrVariable;
    }
}
  • Pokud by výraz mohl způsobit změnu chování, zabalte ho pomocí checked příkazu nebo unchecked zachovejte předchozí chování.
using System;

public unsafe class IntPtrTest
{
    IntPtr intPtrVariable;
    long longVariable;

    void Test ()
    {
        checked
        {
            IntPtr result = unchecked(intPtrVariable + 2); // wrap with unchecked

            result = unchecked(intPtrVariable - 2);

            void* voidPtrVariable = unchecked((void*)intPtrVariable);

            result = unchecked((IntPtr)voidPtrVariable);
        }

        intPtrVariable = checked((IntPtr)longVariable); // wrap with checked

        int a = checked((int)intPtrVariable);
    }
}

Kdy potlačit upozornění

Pokud výraz nezpůsobí změnu chování, je bezpečné potlačit upozornění z tohoto pravidla.

Viz také