Поделиться через


CA2020: предотвращение изменения поведения, вызванного встроенными операторами IntPtr/UIntPtr

Свойство Значение
Идентификатор правила CA2020
Заголовок Предотвращение изменения поведения, вызванного встроенными операторами IntPtr/UIntPtr
Категория Надежность
Исправление является критическим или не критическим Не критическое
Включен по умолчанию в .NET 9 Как предложение

Причина

Это правило возникает при обнаружении изменения поведения между .NET 6 и .NET 7, представленными новыми встроенными операторами IntPtr и UIntPtr.

Описание правила

Благодаря числовым функциямIntPtr IntPtr и UIntPtr встроенным операторам для преобразований, унарных операций и двоичных операций. Эти операторы могут вызываться при переполнении в проверяемом контексте или не могут вызываться в незаверченном контексте по сравнению с предыдущими пользовательскими операторами в .NET 6 и более ранних версиях. Это изменение поведения может возникнуть при обновлении до .NET 7.

Список затронутых API

Оператор Контекст В .NET 7 В .NET 6 и более ранних версиях Пример
оператор +(IntPtr, int) включен Вызывается при переполнении Не вызывается при переполнении checked(intPtrVariable + 2);
оператор -(IntPtr, int) включен Вызывается при переполнении Не вызывается при переполнении checked(intPtrVariable - 2);
явный оператор IntPtr(long) не включен Не вызывается при переполнении Может вызываться в 32-разрядных контекстах (IntPtr)longVariable;
явный оператор void*(IntPtr) включен вызывается при переполнении Не вызывается при переполнении checked((void*)intPtrVariable);
явный оператор IntPtr(void*) включен вызывается при переполнении Не вызывается при переполнении checked((IntPtr)voidPtrVariable);
явный оператор int(IntPtr) не включен Не вызывается при переполнении Может вызываться в 64-разрядных контекстах (int)intPtrVariable;
оператор +(UIntPtr, int) включен Вызывается при переполнении Не вызывается при переполнении checked(uintPtrVariable + 2);
оператор -(UIntPtr, int) включен Вызывается при переполнении Не вызывается при переполнении checked(uintPtrVariable - 2);
явный оператор UIntPtr(ulong) не включен Не вызывается при переполнении Может вызываться в 32-разрядных контекстах (UIntPtr)uLongVariable
явный оператор uint(UIntPtr) не включен Не вызывается при переполнении Может вызываться в 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);
    }
}

Когда лучше отключить предупреждения

Если выражение не приведет к изменению поведения, это безопасно для подавления предупреждения из этого правила.

См. также