https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118665
--- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Currently the hanging program is a clue that your URBG is broken and should not
be used. If we applied the patch above then we would hide the brokenness, which
is not necessarily an improvement.
An assertion would point the problem out again, although even with a higher
maximum, it's still a non-zero probability of this assertion firing for a valid
URBG that just happens to return a low value 2^n times in a row.
-- a/libstdc++-v3/include/bits/uniform_int_dist.h
+++ b/libstdc++-v3/include/bits/uniform_int_dist.h
@@ -271,11 +271,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__low < __range)
{
_Up __threshold = -__range % __range;
- while (__low < __threshold)
+ constexpr _Up __max_tries = 32; // defend against a broken URGB
+ _Up __tries = __max_tries;
+ while (__low < __threshold && __builtin_expect(__tries--, true))
{
__product = _Wp(__g()) * _Wp(__range);
__low = _Up(__product);
}
+ __glibcxx_assert(__tries < __max_tries);
}
return __product >> _Up_traits::__digits;
}
On the other hand, users can provide a URBG that is broken in different ways,
which would still produce garbage from uniform_int_distribution even though it
doesn't get stuck in the rejection loop, e.g. the https://xkcd.com/221/ RNG:
result_type operator()() { return 4; }