<random>: independent_bits_engine performs forbidden full shifts (original) (raw)
Found by Clang 20 UBSan in P0952R2_new_generate_canonical's usage of independent_bits_engine. Reduced:
D:\GitHub\STL\out\x64>type meow.cpp
#include #include #include #include #include using namespace std;
template <class Engine, size_t W> void test(const string_view name) { println("test<{}, {}>():", name, W); independent_bits_engine<Engine, W, uint64_t> ibe; const auto val = ibe(); println("val: {}", val); println(); }
int main() { test<mt19937_64, 64>("mt19937_64"); test<mt19937, 64>("mt19937"); test<mt19937, 32>("mt19937"); }
D:\GitHub\STL\out\x64>clang-cl /EHsc /nologo /W4 /std:c++latest -fsanitize=undefined meow.cpp /Zi /Fdmeow.pdb /link /ignore:4217 && meow
Creating library meow.lib and object meow.exp
test<mt19937_64, 64>():
D:\GitHub\STL\out\x64\out\inc\random:1977:25: runtime error: shift exponent 64 is too large for 64-bit type '_Eres' (aka 'unsigned long long')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:\GitHub\STL\out\x64\out\inc\random:1977:25
D:\GitHub\STL\out\x64\out\inc\random:1977:34: runtime error: shift exponent 64 is too large for 64-bit type '_Eres' (aka 'unsigned long long')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:\GitHub\STL\out\x64\out\inc\random:1977:34
D:\GitHub\STL\out\x64\out\inc\random:1978:27: runtime error: shift exponent 64 is too large for 64-bit type '_Eres' (aka 'unsigned long long')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:\GitHub\STL\out\x64\out\inc\random:1978:27
D:\GitHub\STL\out\x64\out\inc\random:1978:42: runtime error: shift exponent 64 is too large for 64-bit type '_Eres' (aka 'unsigned long long')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:\GitHub\STL\out\x64\out\inc\random:1978:42
D:\GitHub\STL\out\x64\out\inc\random:1915:25: runtime error: shift exponent 64 is too large for 64-bit type 'result_type' (aka 'unsigned long long')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:\GitHub\STL\out\x64\out\inc\random:1915:25
val: 14514284786278117030
test<mt19937, 64>():
D:\GitHub\STL\out\x64\out\inc\random:1977:25: runtime error: shift exponent 32 is too large for 32-bit type '_Eres' (aka 'unsigned int')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:\GitHub\STL\out\x64\out\inc\random:1977:25
D:\GitHub\STL\out\x64\out\inc\random:1977:34: runtime error: shift exponent 32 is too large for 32-bit type '_Eres' (aka 'unsigned int')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:\GitHub\STL\out\x64\out\inc\random:1977:34
D:\GitHub\STL\out\x64\out\inc\random:1978:27: runtime error: shift exponent 32 is too large for 32-bit type '_Eres' (aka 'unsigned int')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:\GitHub\STL\out\x64\out\inc\random:1978:27
D:\GitHub\STL\out\x64\out\inc\random:1978:42: runtime error: shift exponent 32 is too large for 32-bit type '_Eres' (aka 'unsigned int')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:\GitHub\STL\out\x64\out\inc\random:1978:42
val: 15028999435905310454
test<mt19937, 32>():
D:\GitHub\STL\out\x64\out\inc\random:1977:25: runtime error: shift exponent 32 is too large for 32-bit type '_Eres' (aka 'unsigned int')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:\GitHub\STL\out\x64\out\inc\random:1977:25
D:\GitHub\STL\out\x64\out\inc\random:1977:34: runtime error: shift exponent 32 is too large for 32-bit type '_Eres' (aka 'unsigned int')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:\GitHub\STL\out\x64\out\inc\random:1977:34
D:\GitHub\STL\out\x64\out\inc\random:1978:27: runtime error: shift exponent 32 is too large for 32-bit type '_Eres' (aka 'unsigned int')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:\GitHub\STL\out\x64\out\inc\random:1978:27
D:\GitHub\STL\out\x64\out\inc\random:1978:42: runtime error: shift exponent 32 is too large for 32-bit type '_Eres' (aka 'unsigned int')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:\GitHub\STL\out\x64\out\inc\random:1978:42
val: 3499211612
Affected lines:
| _Yx0 = (_Rx >> _Wx0) << _Wx0; |
|---|
| _Yx1 = (((_Rx >> _Wx0) >> 1) << _Wx0) << 1; |
| _Res = _Res << _Wx0 | (static_cast<result_type>(_Val) & _Mask); |
|---|
I am suspicious of this line, but I haven't found a case to trigger it yet:
| _Res = _Res << (_Wx0 + 1) | (static_cast<result_type>(_Val) & _Mask); |
|---|