CA2020: impedir alteração comportamental causada por operadores internos de IntPtr/UIntPtr

Property Valor
ID da regra CA2020
Título Impeça a alteração comportamental causada por operadores internos de IntPtr/UIntPtr
Categoria Confiabilidade
Correção interruptiva ou sem interrupção Sem interrupção
Habilitado por padrão no .NET 8 Como sugestão

Causa

Essa regra é acionada quando detecta 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 IntPtr numérico, IntPtr e UIntPtr ganhou operadores internos para conversões, operações unárias e operações binárias. Esses operadores podem ser gerados quando transbordam dentro do contexto verificado ou podem não gerar contexto não verificado em comparação com os operadores definidos pelo usuário anteriores no .NET 6 e versões anteriores. Você poderá encontrar essa alteração comportamental ao atualizar para o .NET 7.

Lista de APIs afetadas

Operador Contexto No .NET 7 No .NET 6 e anterior Exemplo
operador +(IntPtr, int) verificado É lançado quando estoura Não é lançado quando estoura checked(intPtrVariable + 2);
operador -(IntPtr, int) verificado É lançado quando estoura Não é lançado quando estoura checked(intPtrVariable - 2);
operador explícito IntPtr(long) unchecked Não é lançado quando estoura Pode lançar contextos de 32 bits (IntPtr)longVariable;
operador explícito void*(IntPtr) verificado é lançado quando estoura Não é lançado quando estoura checked((void*)intPtrVariable);
operador explícito IntPtr(void*) verificado é lançado quando estoura Não é lançado quando estoura checked((IntPtr)voidPtrVariable);
operador explícito int(IntPtr) unchecked Não é lançado quando estoura Pode lançar contextos de 64 bits (int)intPtrVariable;
operador +(UIntPtr, int) verificado É lançado quando estoura Não é lançado quando estoura checked(uintPtrVariable + 2);
operador -(UIntPtr, int) verificado É lançado quando estoura Não é lançado quando estoura checked(uintPtrVariable - 2);
operador explícito UIntPtr(ulong) unchecked Não é lançado quando estoura Pode lançar contextos de 32 bits (UIntPtr)uLongVariable
operador explícito uint(UIntPtr) unchecked Não é lançado quando estoura Pode lançar 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 das seguintes opções:

Opções de correção:

  • Se a expressão não causar uma alteração comportamental:
    • Se o tipo IntPtr ou UIntPtr for usado como um int ou uint nativo, altere o tipo para nint ou nuint.
    • Se o tipo IntPtr ou UIntPtr for usado como um ponteiro nativo, altere o tipo para o tipo de ponteiro nativo correspondente.
    • Se você não puder alterar o tipo da variável, suprima o aviso.
  • Se a expressão puder causar uma alteração comportamental, encapsule-a com uma instrução checked 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 alteração comportamental e o tipo IntPtr ou UIntPtr for usado como um nativo int ou uint, altere o tipo para nint ou 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;
    }
}
  • Se a expressão puder causar uma alteração comportamental, encapsule-a com uma instrução checked 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 alteração comportamental, será seguro suprimir um aviso dessa regra.

Confira também