Partilhar via


CA2020: Prevenir mudanças comportamentais causadas por operadores integrados de IntPtr/UIntPtr

Property valor
ID da regra CA2020
Título Prevenir alterações comportamentais causadas por operadores internos de IntPtr/UIntPtr
Categoria Fiabilidade
A correção está quebrando ou não quebrando Sem quebra
Habilitado por padrão no .NET 8 Como sugestão

Motivo

Esta regra é acionada quando deteta uma alteração comportamental entre o .NET 6 e o .NET 7 introduzida pelos novos operadores internos de IntPtr e UIntPtr.

Descrição da regra

Com o recurso numérico IntPtr, IntPtr e ganhou operadores internos para conversões, operações unárias e UIntPtr operações binárias. Esses operadores podem lançar quando estouro dentro do contexto verificado ou podem não lançar em contexto não verificado em comparação com os operadores anteriores definidos pelo usuário no .NET 6 e versões anteriores. Você pode encontrar essa alteração comportamental ao atualizar para o .NET 7.

Lista de APIs afetadas

Operador Contexto No .NET 7 No .NET 6 e versões anteriores Exemplo
operador +(IntPtr, int) verificado Lança quando transborda Não joga quando transborda checked(intPtrVariable + 2);
operador -(IntPtr, int) verificado Lança quando transborda Não joga quando transborda checked(intPtrVariable - 2);
operador explícito IntPtr(long) não verificado Não joga quando transborda Pode lançar em contextos de 32 bits (IntPtr)longVariable;
operador explícito void*(IntPtr) verificado lança quando transborda Não joga quando transborda checked((void*)intPtrVariable);
operador explícito IntPtr(void*) verificado lança quando transborda Não joga quando transborda checked((IntPtr)voidPtrVariable);
operador explícito int(IntPtr) não verificado Não joga quando transborda Pode lançar em contextos de 64 bits (int)intPtrVariable;
operador +(UIntPtr, int) verificado Lança quando transborda Não joga quando transborda checked(uintPtrVariable + 2);
operador -(UIntPtr, int) verificado Lança quando transborda Não joga quando transborda checked(uintPtrVariable - 2);
operador explícito UIntPtr(ulong) não verificado Não joga quando transborda Pode lançar em contextos de 32 bits (UIntPtr)uLongVariable
operador explícito uint(UIntPtr) não verificado Não joga quando transborda Pode lançar em contextos de 64 bits (uint)uintPtrVariable

Como corrigir violações

Examine seu código para determinar se a expressão sinalizada pode causar uma alteração comportamental e escolha uma maneira apropriada de corrigir o diagnóstico a partir das seguintes opções:

Opções de correção:

  • Se a expressão não causar uma mudança comportamental:
    • Se o tipo ou for usado como nativo ou , altere o IntPtr tipo para nint ou nuintUIntPtruint.int
    • Se o tipo ou for usado como um ponteiro nativo, altere UIntPtr o tipo para o IntPtr tipo de ponteiro nativo correspondente.
    • Se não for possível alterar o tipo da variável, suprima o aviso.
  • Se a expressão puder causar uma mudança comportamental, envolva-a com uma checked declaração ou unchecked para preservar o comportamento anterior.

Exemplo

Violação:

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

Correção:

  • Se a expressão não causar uma mudança comportamental e o tipo ou for usado como nativo ou , altere o IntPtr tipo para nint ou UIntPtruintnuint.int
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;
    }
}
  • Se a expressão puder causar uma mudança comportamental, envolva-a com uma checked declaração ou unchecked para preservar o comportamento anterior.
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);
    }
}

Quando suprimir avisos

Se a expressão não causar uma mudança de comportamento, é seguro suprimir um aviso dessa regra.

Consulte também