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.
| 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 10 | 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
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, será seguro suprimir um aviso dessa regra.