Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
| 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 10 | 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 UIntPtr ganhou operadores internos para conversões, operações unárias e operações binárias. Esses operadores podem lançar quando estouro dentro do contexto verificado ou não podem 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
IntPtrtipo ou for usado como nativoUIntPtrouint, altereuinto tipo paranintounuint. - Se o
IntPtrtipo ou for usado como um ponteiro nativo, altereUIntPtro tipo para o tipo de ponteiro nativo correspondente. - Se não for possível alterar o tipo da variável, suprima o aviso.
- Se o
- Se a expressão puder causar uma mudança comportamental, envolva-a com uma
checkeddeclaração ouuncheckedpara 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
IntPtrtipo ouUIntPtrfor usado como 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 mudança comportamental, envolva-a com uma
checkeddeclaração ouuncheckedpara 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 comportamental, é seguro suprimir um aviso dessa regra.