-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Fix panic when using EqualValues with uncomparable types #1825
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -177,21 +177,49 @@ func ObjectsAreEqualValues(expected, actual interface{}) bool { | |||||||||||||||||||||||||||||||||
| return false | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| // Attempt conversion of expected to actual type | ||||||||||||||||||||||||||||||||||
| // This handles more cases than just the ConvertibleTo check above | ||||||||||||||||||||||||||||||||||
| if !expectedValue.CanConvert(actualType) { | ||||||||||||||||||||||||||||||||||
| // Types are not convertible, so they cannot be equal | ||||||||||||||||||||||||||||||||||
| // This prevents panics when calling [reflect.Value.Convert] | ||||||||||||||||||||||||||||||||||
| return false | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| expectedConverted := expectedValue.Convert(actualType) | ||||||||||||||||||||||||||||||||||
| if !expectedConverted.CanInterface() { | ||||||||||||||||||||||||||||||||||
| // Cannot interface after conversion, so cannot be equal | ||||||||||||||||||||||||||||||||||
| // This prevents panics when calling [reflect.Value.Interface] | ||||||||||||||||||||||||||||||||||
| return false | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if !isNumericType(expectedType) || !isNumericType(actualType) { | ||||||||||||||||||||||||||||||||||
| // Attempt comparison after type conversion | ||||||||||||||||||||||||||||||||||
| return reflect.DeepEqual( | ||||||||||||||||||||||||||||||||||
| expectedValue.Convert(actualType).Interface(), actual, | ||||||||||||||||||||||||||||||||||
| expectedConverted.Interface(), actual, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| // If BOTH values are numeric, there are chances of false positives due | ||||||||||||||||||||||||||||||||||
| // to overflow or underflow. So, we need to make sure to always convert | ||||||||||||||||||||||||||||||||||
| // the smaller type to a larger type before comparing. | ||||||||||||||||||||||||||||||||||
| if expectedType.Size() >= actualType.Size() { | ||||||||||||||||||||||||||||||||||
| return actualValue.Convert(expectedType).Interface() == expected | ||||||||||||||||||||||||||||||||||
| if !actualValue.CanConvert(expectedType) { | ||||||||||||||||||||||||||||||||||
| // Cannot convert actual to the expected type, so cannot be equal | ||||||||||||||||||||||||||||||||||
| // This is a hypothetical case to prevent panics when calling [reflect.Value.Convert] | ||||||||||||||||||||||||||||||||||
| return false | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| actualConverted := actualValue.Convert(expectedType) | ||||||||||||||||||||||||||||||||||
| if !actualConverted.CanInterface() { | ||||||||||||||||||||||||||||||||||
| // Cannot interface after conversion, so cannot be equal | ||||||||||||||||||||||||||||||||||
| // This is a hypothetical case to prevent panics when calling [reflect.Value.Convert] | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+208
to
+215
|
||||||||||||||||||||||||||||||||||
| // This is a hypothetical case to prevent panics when calling [reflect.Value.Convert] | |
| return false | |
| } | |
| actualConverted := actualValue.Convert(expectedType) | |
| if !actualConverted.CanInterface() { | |
| // Cannot interface after conversion, so cannot be equal | |
| // This is a hypothetical case to prevent panics when calling [reflect.Value.Convert] | |
| // This handles the same edge case as above to prevent panics when calling [reflect.Value.Convert] | |
| return false | |
| } | |
| actualConverted := actualValue.Convert(expectedType) | |
| if !actualConverted.CanInterface() { | |
| // Cannot interface after conversion, so cannot be equal | |
| // This handles the same edge case as above to prevent panics when calling [reflect.Value.Interface] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to line 208, this comment incorrectly describes this as a "hypothetical case" when it's actually a real protection against runtime panics. The check is necessary and mirrors the protection added at lines 189-192. Consider removing "hypothetical" from the comment or rephrasing to clarify this is a real edge case being handled.