0
0
mirror of https://gitlab.com/libeigen/eigen.git synced 2026-01-18 17:31:19 +01:00

fix UB in random implementation and tests

libeigen/eigen!2102
This commit is contained in:
Charles Schlosser
2025-12-31 03:57:04 +00:00
committed by Antonio Sánchez
parent c5aa40675a
commit c30af8f3db
3 changed files with 15 additions and 10 deletions

View File

@@ -56,19 +56,21 @@ struct random_bits_impl {
EIGEN_STATIC_ASSERT(std::is_unsigned<Scalar>::value, SCALAR MUST BE A BUILT - IN UNSIGNED INTEGER)
using RandomDevice = eigen_random_device;
using RandomReturnType = typename RandomDevice::ReturnType;
static constexpr int kEntropy = RandomDevice::Entropy;
static constexpr int kTotalBits = sizeof(Scalar) * CHAR_BIT;
static constexpr int kEntropy = plain_enum_min(kTotalBits, RandomDevice::Entropy);
// return a Scalar filled with numRandomBits beginning from the least significant bit
static EIGEN_DEVICE_FUNC inline Scalar run(int numRandomBits) {
eigen_assert((numRandomBits >= 0) && (numRandomBits <= kTotalBits));
const Scalar mask = Scalar(-1) >> ((kTotalBits - numRandomBits) & (kTotalBits - 1));
Scalar randomBits = 0;
for (int shift = 0; shift < numRandomBits; shift += kEntropy) {
RandomReturnType r = RandomDevice::run();
randomBits |= static_cast<Scalar>(r) << shift;
for (int filledBits = 0; filledBits < numRandomBits; filledBits += kEntropy) {
Scalar r = static_cast<Scalar>(RandomDevice::run());
int remainingBits = numRandomBits - filledBits;
if (remainingBits < kEntropy) {
// clear the excess bits to avoid UB and rounding bias
r >>= kEntropy - remainingBits;
}
randomBits |= r << filledBits;
}
// clear the excess bits
randomBits &= mask;
return randomBits;
}
};
@@ -204,7 +206,8 @@ struct random_int_impl<Scalar, false, true> {
template <typename Scalar>
struct random_int_impl<Scalar, true, true> {
static constexpr int kTotalBits = sizeof(Scalar) * CHAR_BIT;
using BitsType = typename make_unsigned<Scalar>::type;
// avoid implicit integral promotion to `int`
using BitsType = std::conditional_t<(sizeof(Scalar) < sizeof(int)), unsigned int, std::make_unsigned_t<Scalar> >;
static EIGEN_DEVICE_FUNC inline Scalar run(const Scalar& x, const Scalar& y) {
if (y <= x) return x;
// Avoid overflow by representing `range` as an unsigned type

View File

@@ -721,7 +721,7 @@ EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC float half_to_float(__half_raw h) {
o_bits = Eigen::numext::bit_cast<uint32_t>(Eigen::numext::bit_cast<float>(o_bits) - magic);
}
o_bits |= (h.x & 0x8000) << 16; // sign bit
o_bits |= (h.x & 0x8000u) << 16; // sign bit
return Eigen::numext::bit_cast<float>(o_bits);
#endif
}

View File

@@ -83,7 +83,9 @@ class HistogramHelper {
// helper class to avoid extending std:: namespace
template <typename T>
struct get_range_type : internal::make_unsigned<T> {};
struct get_range_type {
using type = std::conditional_t<(sizeof(T) < sizeof(int)), unsigned int, std::make_unsigned_t<T>>;
};
template <typename T>
struct get_range_type<SafeScalar<T>> : internal::make_unsigned<T> {};