Udostępnij za pośrednictwem


CA2020: Zapobieganie zmianom behawioralnym spowodowanym przez wbudowane operatory intPtr/UIntPtr

Właściwości Wartość
Identyfikator reguły CA2020
Tytuł Zapobieganie zmianom zachowania spowodowanym przez wbudowane operatory intPtr/UIntPtr
Kategoria Niezawodność
Poprawka powodująca niezgodność lub niezgodność Niezgodność
Domyślnie włączone na platformie .NET 9 Jako sugestia

Przyczyna

Ta reguła jest uruchamiana, gdy wykrywa zmianę zachowania między platformami .NET 6 i .NET 7 wprowadzonymi przez nowe wbudowane operatory systemów IntPtr i UIntPtr.

Opis reguły

Dzięki funkcjiIntPtr liczbowej IntPtr i UIntPtr zyskaliśmy wbudowane operatory konwersji, operacji jednoargumentowych i operacji binarnych. Te operatory mogą zgłaszać przepełnienie w ramach zaznaczonego kontekstu lub nie mogą zgłaszać niezaznaczonego kontekstu w porównaniu z poprzednimi operatorami zdefiniowanymi przez użytkownika na platformie .NET 6 i starszych wersjach. Ta zmiana zachowania może wystąpić podczas uaktualniania do platformy .NET 7.

Lista interfejsów API, których dotyczy problem

Operator Kontekst Na platformie .NET 7 W programie .NET 6 i starszych wersjach Przykład
operator +(IntPtr, int) checked Zgłasza przy przepełnieniu Nie zgłasza się, gdy przepełnienie checked(intPtrVariable + 2);
operator -(IntPtr, int) checked Zgłasza przy przepełnieniu Nie zgłasza się, gdy przepełnienie checked(intPtrVariable - 2);
jawny operator IntPtr(long) unchecked Nie zgłasza się, gdy przepełnienie Może zgłaszać w kontekstach 32-bitowych (IntPtr)longVariable;
jawny operator void*(IntPtr) checked zgłaszane w przypadku przepełnienia Nie zgłasza się, gdy przepełnienie checked((void*)intPtrVariable);
jawny operator IntPtr(void*) checked zgłaszane w przypadku przepełnienia Nie zgłasza się, gdy przepełnienie checked((IntPtr)voidPtrVariable);
jawny operator int(IntPtr) unchecked Nie zgłasza się, gdy przepełnienie Może zgłaszać w kontekstach 64-bitowych (int)intPtrVariable;
operator +(UIntPtr, int) checked Zgłasza przy przepełnieniu Nie zgłasza się, gdy przepełnienie checked(uintPtrVariable + 2);
operator -(UIntPtr, int) checked Zgłasza przy przepełnieniu Nie zgłasza się, gdy przepełnienie checked(uintPtrVariable - 2);
jawny operator UIntPtr(ulong) unchecked Nie zgłasza się, gdy przepełnienie Może zgłaszać w kontekstach 32-bitowych (UIntPtr)uLongVariable
jawny operator uint(UIntPtr) unchecked Nie zgłasza się, gdy przepełnienie Może zgłaszać w kontekstach 64-bitowych (uint)uintPtrVariable

Jak naprawić naruszenia

Sprawdź swój kod, aby ustalić, czy oflagowane wyrażenie może spowodować zmianę zachowania, i wybierz odpowiedni sposób naprawy diagnostyki z następujących opcji:

Opcje naprawy:

  • Jeśli wyrażenie nie spowoduje zmiany behawioralnej:
    • IntPtr Jeśli typ lub UIntPtr jest używany jako natywny int lub uint, zmień typ na nint lub nuint.
    • IntPtr Jeśli typ lub UIntPtr jest używany jako wskaźnik macierzysty, zmień typ na odpowiedni natywny typ wskaźnika.
    • Jeśli nie możesz zmienić typu zmiennej, pomiń ostrzeżenie.
  • Jeśli wyrażenie może spowodować zmianę zachowania, opakuj je za pomocą checked instrukcji lub unchecked , aby zachować poprzednie zachowanie.

Przykład

Naruszenie:

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

Poprawka:

  • Jeśli wyrażenie nie spowoduje zmiany zachowania, a IntPtr typ lub UIntPtr jest używany jako natywny int lub uint, zmień typ na nint lub 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;
    }
}
  • Jeśli wyrażenie może spowodować zmianę zachowania, opakuj je za pomocą checked instrukcji lub unchecked , aby zachować poprzednie zachowanie.
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);
    }
}

Kiedy pomijać ostrzeżenia

Jeśli wyrażenie nie spowoduje zmiany behawioralnej, można bezpiecznie pominąć ostrzeżenie z tej reguły.

Zobacz też