Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
| Propriedade | 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 | Inquebrável |
| Habilitado por padrão no .NET 10 | Como sugestão |
| Idiomas aplicáveis | C# |
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 lançar exceção quando há transbordamento em um contexto verificado ou podem não lançar exceção em um contexto não verificado, comparado aos operadores definidos pelo usuário em .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 versões anteriores | Exemplo |
|---|---|---|---|---|
| operador +(IntPtr, int) | verificado | Dispara quando ocorre estouro | Não gera exceção quando ocorre transbordamento | checked(intPtrVariable + 2); |
| operador -(IntPtr, int) | verificado | Lança ao ocorrer transbordamento | Não é lançado quando estoura | checked(intPtrVariable - 2); |
| operador explícito IntPtr(long) | desmarcado | 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) | não verificado | Não é lançado quando estoura | Pode lançar contextos de 64 bits | (int)intPtrVariable; |
| operador +(UIntPtr, int) | verificado | Lança ao ocorrer transbordamento | Não é lançado quando estoura | checked(uintPtrVariable + 2); |
| operador -(UIntPtr, int) | verificado | Lança ao ocorrer transbordamento | Não é lançado quando estoura | checked(uintPtrVariable - 2); |
| operador explícito UIntPtr(ulong) | não verificado | Não é lançado quando estoura | Pode lançar contextos de 32 bits | (UIntPtr)uLongVariable |
| operador explícito uint(UIntPtr) | não verificado | 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
IntPtrouUIntPtrfor usado como umintouuintnativo, altere o tipo paranintounuint. - Se o tipo
IntPtrouUIntPtrfor 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 o tipo
- Se a expressão puder causar uma alteração comportamental, encapsule-a com uma instrução
checkedouuncheckedpara 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
IntPtrouUIntPtrfor usado como um nativointouuint, altere o tipo paranintounuint.
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
checkedouuncheckedpara 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, está seguro suprimir um aviso desta regra.