diff --git a/llvm/lib/Support/Windows/Process.inc b/llvm/lib/Support/Windows/Process.inc index 518ecdb9889627..6eb4a5eb7457ae 100644 --- a/llvm/lib/Support/Windows/Process.inc +++ b/llvm/lib/Support/Windows/Process.inc @@ -439,18 +439,38 @@ const char *Process::ResetColor() { return 0; } +static unsigned GetRandomNumberSeed() { + // Generate a random number seed from the millisecond-resolution Windows + // system clock and the current process id. + FILETIME Time; + GetSystemTimeAsFileTime(&Time); + DWORD Pid = GetCurrentProcessId(); + return hash_combine(Time.dwHighDateTime, Time.dwLowDateTime, Pid); +} + +static unsigned GetPseudoRandomNumber() { + // Arrange to call srand once when this function is first used, and + // otherwise (if GetRandomNumber always succeeds in using + // CryptGenRandom) don't bother at all. + static int x = (static_cast(::srand(GetRandomNumberSeed())), 0); + (void)x; + return ::rand(); +} + unsigned Process::GetRandomNumber() { + // Try to use CryptGenRandom. HCRYPTPROV HCPC; - if (!::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) - ReportLastErrorFatal("Could not acquire a cryptographic context"); - - ScopedCryptContext CryptoProvider(HCPC); - unsigned Ret; - if (!::CryptGenRandom(CryptoProvider, sizeof(Ret), - reinterpret_cast(&Ret))) - ReportLastErrorFatal("Could not generate a random number"); - return Ret; + if (::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) { + ScopedCryptContext CryptoProvider(HCPC); + unsigned Ret; + if (::CryptGenRandom(CryptoProvider, sizeof(Ret), + reinterpret_cast(&Ret))) + return Ret; + } + + // If that fails, fall back to pseudo-random numbers. + return GetPseudoRandomNumber(); } typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);