diff options
Diffstat (limited to 'src/corelib/tools')
-rw-r--r-- | src/corelib/tools/qsimd.cpp | 68 | ||||
-rw-r--r-- | src/corelib/tools/qsimd_p.h | 18 | ||||
-rw-r--r-- | src/corelib/tools/qvarlengtharray.h | 2 |
3 files changed, 87 insertions, 1 deletions
diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp index ecf1822e42..fb9b5996f6 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) noexcept +{ + 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 diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h index db2f546651..c28624a25e 100644 --- a/src/corelib/tools/qsimd_p.h +++ b/src/corelib/tools/qsimd_p.h @@ -346,6 +346,15 @@ extern Q_CORE_EXPORT QBasicAtomicInteger<unsigned> qt_cpu_features[2]; #endif Q_CORE_EXPORT quint64 qDetectCpuFeatures(); +#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND) +Q_CORE_EXPORT qsizetype qRandomCpu(void *, qsizetype) noexcept; +#else +static inline qsizetype qRandomCpu(void *, qsizetype) noexcept +{ + return 0; +} +#endif + static inline quint64 qCpuFeatures() { quint64 features = qt_cpu_features[0].loadRelaxed(); @@ -362,6 +371,15 @@ static inline quint64 qCpuFeatures() #define qCpuHasFeature(feature) (((qCompilerCpuFeatures & CpuFeature ## feature) == CpuFeature ## feature) \ || ((qCpuFeatures() & CpuFeature ## feature) == CpuFeature ## feature)) +inline bool qHasHwrng() +{ +#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND) + return qCpuHasFeature(RDRND); +#else + return false; +#endif +} + #define ALIGNMENT_PROLOGUE_16BYTES(ptr, i, length) \ for (; i < static_cast<int>(qMin(static_cast<quintptr>(length), ((4 - ((reinterpret_cast<quintptr>(ptr) >> 2) & 0x3)) & 0x3))); ++i) diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index 253d05ba2b..6be695e317 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -104,7 +104,7 @@ public: QVarLengthArray<T, Prealloc> &operator=(std::initializer_list<T> list) { - resize(list.size()); + resize(int(list.size())); // ### q6sizetype std::copy(list.begin(), list.end(), QT_MAKE_CHECKED_ARRAY_ITERATOR(this->begin(), this->size())); return *this; |