CA2020: Verhindern von Verhaltensänderungen durch integrierte Operatoren von IntPtr/UIntPtr
Eigenschaft | Wert |
---|---|
Regel-ID | CA2020 |
Titel | Verhindern von Verhaltensänderungen durch integrierte Operatoren von IntPtr/UIntPtr |
Kategorie | Zuverlässigkeit |
Fix führt oder führt nicht zur Unterbrechung | Nicht unterbrechend |
Standardmäßig in .NET 9 aktiviert | Als Vorschlag |
Ursache
Diese Regel wird ausgelöst, wenn sie eine Verhaltensänderung zwischen .NET 6 und .NET 7 erkennt, die von den neuen integrierten Operatoren von IntPtr und UIntPtr verursacht wurde.
Regelbeschreibung
Mit dem numerischen IntPtr-Feature haben IntPtr und UIntPtr integrierte Operatoren für Konvertierungen, unäre Vorgänge und binäre Vorgänge erhalten. Im Vergleich zu den früheren benutzerdefinierten Operatoren in .NET 6 und früheren Versionen können diese Operatoren bei einem Überlauf im geprüften Kontext einen Fehler verursachen oder im ungeprüften Kontext keinen Fehler verursachen. Diese Verhaltensänderung kann beim Upgrade auf .NET 7 auftreten.
Liste der betroffenen APIs
Operator | Kontext | In .NET 7 | In .NET 6 und früher | Beispiel |
---|---|---|---|---|
Operator +(IntPtr, int) | checked | Löst bei Überläufen einen Fehler aus | Löst bei Überläufen keinen Fehler aus | checked(intPtrVariable + 2); |
Operator -(IntPtr, int) | checked | Löst bei Überläufen einen Fehler aus | Löst bei Überläufen keinen Fehler aus | checked(intPtrVariable - 2); |
Expliziter Operator IntPtr(long) | unchecked | Löst bei Überläufen keinen Fehler aus | Kann in 32-Bit-Kontexten einen Fehler auslösen | (IntPtr)longVariable; |
Expliziter Operator void*(IntPtr) | checked | Löst bei Überläufen einen Fehler aus | Löst bei Überläufen keinen Fehler aus | checked((void*)intPtrVariable); |
Expliziter Operator IntPtr(void*) | checked | Löst bei Überläufen einen Fehler aus | Löst bei Überläufen keinen Fehler aus | checked((IntPtr)voidPtrVariable); |
Expliziter Operator int(IntPtr) | unchecked | Löst bei Überläufen keinen Fehler aus | Kann in 64-Bit-Kontexten einen Fehler auslösen | (int)intPtrVariable; |
Operator +(UIntPtr, int) | checked | Löst bei Überläufen einen Fehler aus | Löst bei Überläufen keinen Fehler aus | checked(uintPtrVariable + 2); |
Operator -(UIntPtr, int) | checked | Löst bei Überläufen einen Fehler aus | Löst bei Überläufen keinen Fehler aus | checked(uintPtrVariable - 2); |
Expliziter Operator UIntPtr(ulong) | unchecked | Löst bei Überläufen keinen Fehler aus | Kann in 32-Bit-Kontexten einen Fehler auslösen | (UIntPtr)uLongVariable |
Expliziter Operator uint(UIntPtr) | unchecked | Löst bei Überläufen keinen Fehler aus | Kann in 64-Bit-Kontexten einen Fehler auslösen | (uint)uintPtrVariable |
Behandeln von Verstößen
Untersuchen Sie Ihren Code darauf, ob der gekennzeichnete Ausdruck einen Behavior Change verursachen könnte, und wählen Sie aus den folgenden Optionen eine geeignete Methode zum Behandeln des Problems aus:
Problembehandlungsoptionen:
- Wenn der Ausdruck keinen Behavior Change verursacht, können Sie Folgendes tun:
- Wenn der
IntPtr
- oderUIntPtr
-Typ als nativerint
- oderuint
-Operator verwendet wird, ändern Sie den Typ innint
odernuint
. - Wenn der
IntPtr
- oderUIntPtr
-Typ als nativer Zeiger verwendet wird, ändern Sie den Typ in den entsprechenden nativen Zeigertyp. - Wenn Sie den Typ der Variablen nicht ändern können, unterdrücken Sie die Warnung.
- Wenn der
- Wenn der Ausdruck einen Behavior Change verursachen könnte, umschließen Sie ihn mit einer
checked
- oderunchecked
-Anweisung, um das vorherige Verhalten beizubehalten.
Beispiel
Verstoß:
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.
}
}
Korrektur:
- Wenn der Ausdruck keinen Behavior Change verursacht und der
IntPtr
- oderUIntPtr
-Typ als nativerint
- oderuint
-Operator verwendet wird, ändern Sie den Typ innint
odernuint
.
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;
}
}
- Wenn der Ausdruck einen Behavior Change verursachen könnte, umschließen Sie ihn mit einer
checked
- oderunchecked
-Anweisung, um das vorherige Verhalten beizubehalten.
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);
}
}
Wann sollten Warnungen unterdrückt werden?
Wenn der Ausdruck keinen Behavior Change verursacht, können Sie eine Warnung dieser Regel ohne Sicherheitsrisiko unterdrücken.