-
Notifications
You must be signed in to change notification settings - Fork 2.9k
[Core] Reject negative values when converting to unsigned #33482
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?
Conversation
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.
Pull request overview
This PR enhances type safety in ov::Any conversions by adding validation for integral type conversions that could result in data loss or unexpected wraparound. The changes prevent silent errors like converting -1 to 4294967295 when casting from signed to unsigned types.
- Adds range checking for signed-to-unsigned and unsigned-to-signed integral conversions
- Rejects negative signed values when converting to unsigned types
- Validates that values fit within target type's numeric limits before conversion
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (std::is_signed<T>::value) { | ||
| if (value > static_cast<unsigned long long>(std::numeric_limits<T>::max())) { | ||
| OPENVINO_THROW("Bad cast (out of range) from ", value, " to: ", typeid(T).name()); | ||
| } | ||
| } else { | ||
| if (value > static_cast<unsigned long long>(std::numeric_limits<T>::max())) { | ||
| OPENVINO_THROW("Bad cast (out of range) from ", value, " to: ", typeid(T).name()); | ||
| } |
Copilot
AI
Jan 6, 2026
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.
The if-else branches for signed vs unsigned target types perform identical checks. Both branches check if the value exceeds the maximum limit of the target type. These branches can be consolidated into a single check that applies to both signed and unsigned target types, reducing code duplication.
| if (std::is_signed<T>::value) { | |
| if (value > static_cast<unsigned long long>(std::numeric_limits<T>::max())) { | |
| OPENVINO_THROW("Bad cast (out of range) from ", value, " to: ", typeid(T).name()); | |
| } | |
| } else { | |
| if (value > static_cast<unsigned long long>(std::numeric_limits<T>::max())) { | |
| OPENVINO_THROW("Bad cast (out of range) from ", value, " to: ", typeid(T).name()); | |
| } | |
| if (value > static_cast<unsigned long long>(std::numeric_limits<T>::max())) { | |
| OPENVINO_THROW("Bad cast (out of range) from ", value, " to: ", typeid(T).name()); |
| if (std::is_integral<T>::value) { | ||
| if (std::is_unsigned<T>::value) { | ||
| if (value < 0) { | ||
| OPENVINO_THROW("Bad cast from signed negative value to unsigned: ", value); |
Copilot
AI
Jan 6, 2026
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.
The error message format is inconsistent with the other error messages in this function. Other range check failures use the format "Bad cast (out of range) from VALUE to: TYPE" (lines 1003, 1008, 1019, 1023), but this message uses a different format. Consider using the consistent format: "Bad cast (out of range) from [value] to: [type]" for uniformity.
| OPENVINO_THROW("Bad cast from signed negative value to unsigned: ", value); | |
| OPENVINO_THROW("Bad cast (out of range) from ", value, " to: ", typeid(T).name()); |
Fix
This PR makes arithmetic conversions in
ov::Anysafe by rejecting invalid integral casts that previously produced silent wraparound or truncation.ov::Any::as<T>()now throws if the value is negative (e.g.,-1can no longer become4294967295).ov::Any::as<T>()now performs range checks usingstd::numeric_limits<T>and throwsov::Exceptionif the value does not fit in the requested type.Tests
ov::Any{-1}.as<uint32_t>()now throws instead of returning a wrapped unsigned value.src/core/tests/any.cpp(AnyTests.AnyAsUnsignedRejectsNegative) to ensure negative signed values don’t silently wrap when converted to unsigned (e.g.,-1 -> 4294967295).ov_core_unit_tests --gtest_filter='*AnyAsUnsignedRejectsNegative*'