-
Notifications
You must be signed in to change notification settings - Fork 4.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Analyzer] Prevent behavioral change in built-in operators for IntPtr and UIntPtr #74022
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
Tagging subscribers to this area: @dotnet/area-system-runtime Issue DetailsRelated to #72348 (comment) With numeric IntPtr feature, System.IntPtr and System.UIntPtr gained some built-in operators (conversions, unary and binary). Those would now throw when overflowing within checked context, which is causing behavioral change in .NET 7 Detect places where the addition, subtraction, and explicit cast operators were used on
Suggested severity : "Warning" CC @tannergooding @jeffhandley
|
Example: public unsafe class IntPtrTest
{
IntPtr intPtr1;
IntPtr intPtr2;
UIntPtr uintPtr1;
UIntPtr uintPtr2;
long longValue;
long uLongValue;
void Test ()
{
// IntPtr flag code:
checked
{
intPtr2 = intPtr1 + 2; // operator +(IntPtr, int)
intPtr2 = intPtr1 - 2; // operator -(IntPtr, int)
void* ptr = (void*)intPtr1; // explicit operator void*(IntPtr), overflows for values like -1
intPtr2 = (IntPtr)ptr; // explicit operator IntPtr(void*)
}
intPtr1 = (IntPtr)longValue; // explicit operator IntPtr(long) 32 bit unchecked context
int a = (int)intPtr1; // explicit operator int(IntPtr) 64 bit unchecked context
// Fixed code
checked
{
unchecked
{
intPtr2 = intPtr1 + 2; // maybe suggest the method IntPtr.Add(intPtr1, 2) instead
intPtr2 = intPtr1 - 2; // maybe suggest IntPtr.Subtract(IntPtr, Int32) instead
void* ptr = (void*)intPtr1;
intPtr2 = (IntPtr)ptr;
}
}
checked
{
intPtr1 = (IntPtr)longValue;
a = (int)intPtr1;
}
// --------------------------------------------------------------
// UIntPtr flag code:
checked
{
uintPtr2 = uintPtr1 + 2; // operator +(UIntPtr, int)
uintPtr2 = uintPtr1 - 2; // operator -(UIntPtr, int)
}
uintPtr1 = (UIntPtr)uLongValue; // explicit operator IntPtr(long) 32 bit unchecked context
uint ui = (uint)uintPtr1; // explicit operator uint(UIntPtr) 64 bit unchecked context
// Fixed code:
checked
{
unchecked
{
uintPtr2 = uintPtr1 + 2; // we might want also suggest the Add method instead
uintPtr2 = uintPtr1 - 2; // Subtract method
}
}
checked
{
uintPtr1 = (UIntPtr)uLongValue;
ui = (uint)uintPtr1;
}
}
} |
Behavioral change relative to what? Xamarin |
|
Looks good as proposed. Severity: Warning |
After testing the analyzer with runtime and few other repo we decided to degrade the severity to info level. Also the fix for findings not that simple, might better to convert the type |
Related to #72348 (comment)
With numeric IntPtr feature, System.IntPtr and System.UIntPtr gained some built-in operators (conversions, unary and binary). Those would now throw when overflowing within checked context, which is causing behavioral change in .NET 7
Detect places where the addition, subtraction, and explicit cast operators were used on
U?IntPtr
, while taking the overflow checking context into accountIntPtr
operator +(IntPtr, int)
: Unchecked: same behavior; Checked: may overflow now when it didn't before; Wrap in unchecked context to prevent the overflow and preserve behavioroperator -(IntPtr, int)
: Unchecked: same behavior; Checked: may overflow now when it didn't before; Wrap in unchecked context to prevent the overflow and preserve behaviorexplicit operator IntPtr(long)
: Checked: same behavior; Unchecked: will not throw an overflow exception when it could have before in 32-bit contexts; Wrap in a checked context to ensure the exception will be thrown as before in 32-bit contextsexplicit operator void*(IntPtr)
: Unchecked: same behavior; Checked: may overflow now when it didn't before; Wrap in unchecked context to prevent the overflow and preserve behaviorexplicit operator IntPtr(void*)
: Unchecked: same behavior; Checked: may overflow now when it didn't before; Wrap in unchecked context to prevent the overflow and preserve behaviorexplicit operator int(IntPtr)
: Checked: same behavior; Unchecked: will not throw an overflow exception when it could have before in 64-bit contexts; Wrap in checked context to ensure the exception will be thrown as before in 64-bit contextsUIntPtr
operator +(UIntPtr, int)
: Unchecked: same behavior; Checked: may overflow now when it didn't before; Wrap in unchecked context to prevent the overflow and preserve behavioroperator -(UIntPtr, int)
: Unchecked: same behavior; Checked: may overflow now when it didn't before; Wrap in unchecked context to prevent the overflow and preserve behaviorexplicit operator UIntPtr(ulong)
: Checked: same behavior; Unchecked: will not throw an overflow exception when it could have before in 32-bit contexts; Wrap in a checked context to ensure the exception will be thrown as before in 32-bit contextsexplicit operator uint(UIntPtr)
: Checked: same behavior; Unchecked: will not throw an overflow exception when it could have before in 64-bit contexts; Wrap in checked context to ensure the exception will be thrown as before in 64-bit contextsSystem.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr
is available in corelib as mentioned hereSuggested severity : "Warning"
Suggested category : "Usage" or "Reliability"
CC @tannergooding @jeffhandley
The text was updated successfully, but these errors were encountered: