CA2020: Impedire la modifica comportamentale causata dagli operatori predefiniti di IntPtr/UIntPtr
Proprietà | valore |
---|---|
ID regola | CA2020 |
Title | Impedire la modifica comportamentale causata dagli operatori predefiniti di IntPtr/UIntPtr |
Categoria | Affidabilità |
La correzione causa un'interruzione o meno | Non causa un'interruzione |
Abilitato per impostazione predefinita in .NET 9 | Come suggerimento |
Causa
Questa regola viene attivata quando rileva una modifica comportamentale tra .NET 6 e .NET 7 introdotta dai nuovi operatori predefiniti di IntPtr e UIntPtr.
Descrizione regola
Con la funzionalitàIntPtr Numeric IntPtr e UIntPtr sono stati ottenuti operatori predefiniti per conversioni, operazioni unarie e operazioni binarie. Questi operatori potrebbero generare un'eccezione quando l'overflow all'interno del contesto controllato o potrebbe non generare un contesto deselezionato rispetto agli operatori definiti dall'utente precedenti in .NET 6 e versioni precedenti. È possibile che si verifichi questa modifica comportamentale durante l'aggiornamento a .NET 7.
Elenco delle API interessate
Operatore | Contesto | In .NET 7 | In .NET 6 e versioni precedenti | Esempio |
---|---|---|---|---|
operator +(IntPtr, int) | checked | Genera quando si verifica un overflow | Non genera un'eccezione quando si verifica un overflow | checked(intPtrVariable + 2); |
operator -(IntPtr, int) | checked | Genera quando si verifica un overflow | Non genera un'eccezione quando si verifica un overflow | checked(intPtrVariable - 2); |
Operatore explicit IntPtr(long) | unchecked | Non genera un'eccezione quando si verifica un overflow | Può generare in contesti a 32 bit | (IntPtr)longVariable; |
Operatore explicit void*(IntPtr) | checked | genera quando si verifica un overflow | Non genera un'eccezione quando si verifica un overflow | checked((void*)intPtrVariable); |
Operatore explicit IntPtr(void*) | checked | genera quando si verifica un overflow | Non genera un'eccezione quando si verifica un overflow | checked((IntPtr)voidPtrVariable); |
Operatore explicit int(IntPtr) | unchecked | Non genera un'eccezione quando si verifica un overflow | Può generare un'eccezione in contesti a 64 bit | (int)intPtrVariable; |
operator +(UIntPtr, int) | checked | Genera quando si verifica un overflow | Non genera un'eccezione quando si verifica un overflow | checked(uintPtrVariable + 2); |
operator -(UIntPtr, int) | checked | Genera quando si verifica un overflow | Non genera un'eccezione quando si verifica un overflow | checked(uintPtrVariable - 2); |
Operatore explicit UIntPtr(ulong) | unchecked | Non genera un'eccezione quando si verifica un overflow | Può generare in contesti a 32 bit | (UIntPtr)uLongVariable |
Operatore explicit uint(UIntPtr) | unchecked | Non genera un'eccezione quando si verifica un overflow | Può generare un'eccezione in contesti a 64 bit | (uint)uintPtrVariable |
Come correggere le violazioni
Esaminare il codice per determinare se l'espressione contrassegnata potrebbe causare una modifica comportamentale e scegliere un modo appropriato per correggere la diagnostica dalle opzioni seguenti:
Opzioni di correzione:
- Se l'espressione non provocherebbe una modifica comportamentale:
- Se il
IntPtr
tipo oUIntPtr
viene usato come nativoint
ouint
, modificare il tipo innint
onuint
. - Se il
IntPtr
tipo oUIntPtr
viene usato come puntatore nativo, modificare il tipo nel tipo di puntatore nativo corrispondente. - Se non è possibile modificare il tipo della variabile, eliminare l'avviso.
- Se il
- Se l'espressione potrebbe causare una modifica comportamentale, eseguire il wrapping con un'istruzione
checked
ounchecked
per mantenere il comportamento precedente.
Esempio
Violazione:
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.
}
}
Correzione:
- Se l'espressione non provocherebbe una modifica comportamentale e il
IntPtr
tipo oUIntPtr
viene usato come nativoint
ouint
, modificare il tipo innint
onuint
.
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 l'espressione potrebbe causare una modifica comportamentale, eseguire il wrapping con un'istruzione
checked
ounchecked
per mantenere il comportamento precedente.
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 eliminare gli avvisi
Se l'espressione non provocherebbe una modifica comportamentale, è possibile eliminare un avviso da questa regola.