-
Notifications
You must be signed in to change notification settings - Fork 17
Avoid UB in MSB computation in feistel permutation. #87
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
Conversation
While this has no impact on the actual implementation, the missing check resulted in a failed assertion https://github.com/KarlsruheGraphGeneration/KaGen/blob/1118666271f36a8c71018768e2de459f0e5ff1c3/kagen/tools/random_permutation.h#L297 When the left half is all zeros, `most_significant_bit_set` is undefined and may return arbitrary large values, making this assertion fail in debug builds.
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.
AI suggests something like
template <typename Data>
std::uint8_t most_significant_bit_set(const Data arg) {
static_assert(std::is_unsigned<Data>::value, "Data must be an unsigned integral type.");
// __builtin_clz* are undefined for 0
if (arg == 0) {
return 0;
}
constexpr std::size_t width = std::numeric_limits<Data>::digits; // number of value bits
std::size_t leading_zeros = 0;
if constexpr (width == std::numeric_limits<unsigned int>::digits) {
leading_zeros = static_cast<std::size_t>(__builtin_clz(static_cast<unsigned int>(arg)));
} else if constexpr (width == std::numeric_limits<unsigned long>::digits) {
leading_zeros = static_cast<std::size_t>(__builtin_clzl(static_cast<unsigned long>(arg)));
} else if constexpr (width == std::numeric_limits<unsigned long long>::digits) {
leading_zeros = static_cast<std::size_t>(__builtin_clzll(static_cast<unsigned long long>(arg)));
} else {
static_assert(width == std::numeric_limits<unsigned long long>::digits,
"Unsupported Data width for builtin clz");
}
// 0-based index of the most significant set bit
const std::size_t msb_index = width - 1 - leading_zeros;
return static_cast<std::uint8_t>(msb_index);
}
what do you think?
Do we ever call it with signed integers? If not, we could just a std::is_same_v<unsigned ..., Data>?
|
It's only ever called with |
|
Since the code uses |
|
There might still be happening weird things when the number of vertices to permute is zero, we should rename |
While this has no impact on the actual implementation, the missing
check resulted in a failed assertion
KaGen/kagen/tools/random_permutation.h
Line 297 in 1118666
When the left half is all zeros,
most_significant_bit_setisundefined and may return arbitrary large values, making this assertion
fail in debug builds.