CA2020: IntPtr/UIntPtr の組み込み演算子によって発生する動作変更を防止する
プロパティ | 値 |
---|---|
ルール ID | CA2020 |
Title | IntPtr/UIntPtr の組み込み演算子によって発生する動作変更を防止する |
[カテゴリ] | 信頼性 |
修正が中断ありか中断なしか | なし |
.NET 8 では既定で有効 | 提案として |
原因
この規則は、.NET 6 と .NET 7 の間で、新しい組み込み演算子 IntPtr と UIntPtr がもたらす動作変更が検出された場合に適用されます。
規則の説明
数値 IntPtr 機能を使い、IntPtr と UIntPtr では変換、単項演算、二項演算の組み込み演算子を取得しました。 .NET 6 以前のバージョンにおける以前のユーザー定義演算子と比較して、これらの演算子は、checked コンテキスト内でオーバーフローしたときにスローしたり、unchecked コンテキストでスローしなかったりする場合があります。 .NET 7 にアップグレードする場合に、この動作変更が発生する可能性があります。
影響を受ける API の一覧
演算子 | Context | .NET 7 の場合 | .NET 6 以前の場合 | 例 |
---|---|---|---|---|
演算子 +(IntPtr, int) | checked | オーバーフロー時にスローする | オーバーフロー時にスローしない | checked(intPtrVariable + 2); |
演算子 -(IntPtr, int) | checked | オーバーフロー時にスローする | オーバーフロー時にスローしない | checked(intPtrVariable - 2); |
explicit 演算子 IntPtr(long) | unchecked | オーバーフロー時にスローしない | 32 ビット コンテキストでスローする場合がある | (IntPtr)longVariable; |
explicit 演算子 void*(IntPtr) | checked | オーバーフロー時にスローする | オーバーフロー時にスローしない | checked((void*)intPtrVariable); |
explicit 演算子 IntPtr(void*) | checked | オーバーフロー時にスローする | オーバーフロー時にスローしない | checked((IntPtr)voidPtrVariable); |
explicit 演算子 int(IntPtr) | unchecked | オーバーフロー時にスローしない | 64 ビット コンテキストでスローする場合がある | (int)intPtrVariable; |
演算子 +(UIntPtr, int) | checked | オーバーフロー時にスローする | オーバーフロー時にスローしない | checked(uintPtrVariable + 2); |
演算子 -(UIntPtr, int) | checked | オーバーフロー時にスローする | オーバーフロー時にスローしない | checked(uintPtrVariable - 2); |
explicit 演算子 UIntPtr(ulong) | unchecked | オーバーフロー時にスローしない | 32 ビット コンテキストでスローする場合がある | (UIntPtr)uLongVariable |
explicit 演算子 uint(UIntPtr) | unchecked | オーバーフロー時にスローしない | 64 ビット コンテキストでスローする場合がある | (uint)uintPtrVariable |
違反の修正方法
コードを調べて、フラグが設定された式によって動作変更が発生する可能性があるかどうかを判断し、次のオプションから診断内容を修正する適切な方法を選択します。
修正オプション:
- 式によって動作変更が発生しない場合:
IntPtr
またはUIntPtr
型がネイティブのint
またはuint
として使用されている場合は、型をnint
またはnuint
に変更します。IntPtr
またはUIntPtr
型がネイティブ ポインターとして使用されている場合は、型を対応するネイティブ ポインター型に変更します。- 変数の型を変更できない場合は、警告を抑制します。
- 式によって動作変更が発生する可能性がある場合は、それを
checked
またはunchecked
ステートメントでラップし、以前の動作を保持します。
例
違反:
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.
}
}
修正:
- 式によって動作変更が発生せず、
IntPtr
またはUIntPtr
型がネイティブのint
またはuint
として使用されている場合は、型をnint
またはnuint
に変更します。
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;
}
}
- 式によって動作変更が発生する可能性がある場合は、それを
checked
またはunchecked
ステートメントでラップし、以前の動作を保持します。
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);
}
}
どのようなときに警告を抑制するか
式によって動作変更が発生しない場合は、この規則からの警告を抑制しても安全です。
関連項目
GitHub で Microsoft と共同作業する
このコンテンツのソースは GitHub にあります。そこで、issue や pull request を作成および確認することもできます。 詳細については、共同作成者ガイドを参照してください。
.NET