CA2020: Zabránění změnám chování způsobeným integrovanými operátory IntPtr/UIntPtr
Vlastnost | Hodnota |
---|---|
ID pravidla | CA2020 |
Název | Zabránění změnám chování způsobeným integrovanými operátory IntPtr/UIntPtr |
Kategorie | Spolehlivost |
Oprava způsobující chybu nebo chybu způsobující chybu | Nenarušující |
Povoleno ve výchozím nastavení v .NET 9 | Jako návrh |
Příčina
Toto pravidlo se aktivuje, když zjistí změnu chování mezi .NET 6 a .NET 7 zavedenými novými integrovanými operátory IntPtr a UIntPtr.
Popis pravidla
S numerickou funkcíIntPtr IntPtr a UIntPtr získali integrované operátory pro převody, unární operace a binární operace. Tyto operátory můžou vyvolat přetečení v rámci kontrolovaného kontextu nebo nemusí vyvolat nezaškrtnutý kontext v porovnání s předchozími uživatelem definovanými operátory v .NET 6 a starších verzích. K této změně chování může dojít při upgradu na .NET 7.
Seznam ovlivněných rozhraní API
Operátor | Kontext | V .NET 7 | V .NET 6 a starších verzích | Příklad |
---|---|---|---|---|
operator +(IntPtr, int) | checked | Vyvolá při přetečení | Při přetečení se nehodí | checked(intPtrVariable + 2); |
– (IntPtr, int) | checked | Vyvolá při přetečení | Při přetečení se nehodí | checked(intPtrVariable - 2); |
explicitní operátor IntPtr(long) | unchecked | Při přetečení se nehodí | Může vyvolat 32bitové kontexty | (IntPtr)longVariable; |
explicitní operátor void*(IntPtr) | checked | vyvolá při přetečení | Při přetečení se nehodí | checked((void*)intPtrVariable); |
explicitní operátor IntPtr(void*) | checked | vyvolá při přetečení | Při přetečení se nehodí | checked((IntPtr)voidPtrVariable); |
explicitní operátor int(IntPtr) | unchecked | Při přetečení se nehodí | Může vyvolat 64bitové kontexty | (int)intPtrVariable; |
operator +(UIntPtr, int) | checked | Vyvolá při přetečení | Při přetečení se nehodí | checked(uintPtrVariable + 2); |
– operátor -(UIntPtr, int) | checked | Vyvolá při přetečení | Při přetečení se nehodí | checked(uintPtrVariable - 2); |
explicitní operátor UIntPtr(ulong) | unchecked | Při přetečení se nehodí | Může vyvolat 32bitové kontexty | (UIntPtr)uLongVariable |
explicitní operátor uint(UIntPtr) | unchecked | Při přetečení se nehodí | Může vyvolat 64bitové kontexty | (uint)uintPtrVariable |
Jak opravit porušení
Prozkoumejte kód a zjistěte, jestli výraz s příznakem může způsobit změnu chování, a zvolte vhodný způsob, jak opravit diagnostiku z následujících možností:
Možnosti opravy:
- Pokud výraz nezpůsobí změnu chování:
-
IntPtr
Pokud se typUIntPtr
používá jako nativníint
nebouint
, změňte typ nanint
nebonuint
. -
IntPtr
Pokud se typUIntPtr
používá jako nativní ukazatel, změňte typ na odpovídající nativní typ ukazatele. - Pokud nemůžete změnit typ proměnné, potlačit upozornění.
-
- Pokud by výraz mohl způsobit změnu chování, zabalte ho pomocí
checked
příkazu nebounchecked
zachovejte předchozí chování.
Příklad
Porušení:
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.
}
}
Oprava:
- Pokud výraz nezpůsobí změnu chování a
IntPtr
typ seUIntPtr
použije jako nativníint
nebouint
, změňte typ nanint
nebonuint
.
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;
}
}
- Pokud by výraz mohl způsobit změnu chování, zabalte ho pomocí
checked
příkazu nebounchecked
zachovejte předchozí chování.
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);
}
}
Kdy potlačit upozornění
Pokud výraz nezpůsobí změnu chování, je bezpečné potlačit upozornění z tohoto pravidla.