diff options
author | Dmitry Kazakov <dimula73@gmail.com> | 2019-09-05 10:23:08 +0300 |
---|---|---|
committer | Dmitry Kazakov <dimula73@gmail.com> | 2019-09-26 19:52:50 +0300 |
commit | 5839714d986f28412c9f9ed4801d1bf9378f7b51 (patch) | |
tree | 72f48ba65dbb68ceec5acc65658903bd7eff30ab /src/corelib/tools/qsimd.cpp | |
parent | d5abda313dab0f83873d34b7c4ddbe8d8a06dacf (diff) |
Fix QRandomGenerator initialization on AMD CPUs
Some AMD CPUs (e.g. AMD A4-6250J and AMD Ryzen 3000-series) have a
failing random generation instruction, which always returns
0xffffffff, even when generation was "successful".
This code checks if hardware random generator generates four consecutive
equal numbers. If it does, then we probably have a failing one and
should disable it completely.
Change-Id: I38c87920ca2e8cce4143afbff5e453ce3845d11a
Fixes: QTBUG-69423
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/corelib/tools/qsimd.cpp')
-rw-r--r-- | src/corelib/tools/qsimd.cpp | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp index ddd715f745..09c276c4e0 100644 --- a/src/corelib/tools/qsimd.cpp +++ b/src/corelib/tools/qsimd.cpp @@ -376,6 +376,38 @@ static quint64 detectProcessorFeatures() features &= ~AllAVX512; } +#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND) + /** + * Some AMD CPUs (e.g. AMD A4-6250J and AMD Ryzen 3000-series) have a + * failing random generation instruction, which always returns + * 0xffffffff, even when generation was "successful". + * + * This code checks if hardware random generator generates four consecutive + * equal numbers. If it does, then we probably have a failing one and + * should disable it completely. + * + * https://bugreports.qt.io/browse/QTBUG-69423 + */ + if (features & CpuFeatureRDRND) { + const qsizetype testBufferSize = 4; + unsigned testBuffer[4] = {}; + + const qsizetype generated = qRandomCpu(testBuffer, testBufferSize); + + if (Q_UNLIKELY(generated == testBufferSize && + testBuffer[0] == testBuffer[1] && + testBuffer[1] == testBuffer[2] && + testBuffer[2] == testBuffer[3])) { + + fprintf(stderr, "WARNING: CPU random generator seem to be failing, disable hardware random number generation\n"); + fprintf(stderr, "WARNING: RDRND generated: 0x%x 0x%x 0x%x 0x%x\n", + testBuffer[0], testBuffer[1], testBuffer[2], testBuffer[3]); + + features &= ~CpuFeatureRDRND; + } + } +#endif + return features; } @@ -590,4 +622,40 @@ void qDumpCPUFeatures() puts(""); } +#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND) + +# ifdef Q_PROCESSOR_X86_64 +# define _rdrandXX_step _rdrand64_step +# else +# define _rdrandXX_step _rdrand32_step +# endif + +QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(void *buffer, qsizetype count) Q_DECL_NOTHROW +{ + unsigned *ptr = reinterpret_cast<unsigned *>(buffer); + unsigned *end = ptr + count; + int retries = 10; + + while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) { + if (_rdrandXX_step(reinterpret_cast<qregisteruint *>(ptr))) + ptr += sizeof(qregisteruint)/sizeof(*ptr); + else if (--retries == 0) + goto out; + } + + while (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) { + bool ok = _rdrand32_step(ptr); + if (!ok && --retries) + continue; + if (ok) + ++ptr; + break; + } + +out: + return ptr - reinterpret_cast<unsigned *>(buffer); +} +#endif + + QT_END_NAMESPACE |