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 9 | 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
ouUIntPtr
for usado como umint
ouuint
nativo, altere o tipo paranint
ounuint
. - Se o tipo
IntPtr
ouUIntPtr
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 o tipo
- Se a expressão puder causar uma alteração comportamental, encapsule-a com uma instrução
checked
ouunchecked
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
ouUIntPtr
for usado como um nativoint
ouuint
, altere o tipo paranint
ounuint
.
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
ouunchecked
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.