per private mail I got a bug report about the new RANDOM_NUMBER not
working correctly on windows in certain situations. I think the reason
for this might be an array bounds overflow in the fallback code (in
case /dev/urandom doesn't exist), which this patch fixes.

Also, on Windows the equivalent of /dev/urandom is something called
CryptGenRandom. However, using that seems complicated enough that
without a Windows system to test on I don't want to go there. Slightly
newer versions of windows, however, seem to supply a "rand_s"
function, which ostensibly does the same as CryptGenRandom in a
somewhat easier to use fashion. Unfortunately it seems that this
function is not available in MinGW, but it's present in MinGW-w64, so
one needs a bit of macro guards to check for it. Which this patch

Committed r240309 as obvious/lacking active GFortran windows maintainers.

2016-09-21  Janne Blomqvist  <j...@gcc.gnu.org>

    * intrinsics/random.c (getosrandom): Use rand_s() on
    MinGW-w64. Fix bounds overflow in fallback code.

Janne Blomqvist
diff --git a/libgfortran/intrinsics/random.c b/libgfortran/intrinsics/random.c
index 739dbeb..00f1cb1 100644
--- a/libgfortran/intrinsics/random.c
+++ b/libgfortran/intrinsics/random.c
@@ -24,6 +24,9 @@ a copy of the GCC Runtime Library Exception along with this program;
 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 <http://www.gnu.org/licenses/>.  */
+/* For rand_s.  */
+#define _CRT_RAND_S
 #include "libgfortran.h"
 #include <gthr.h>
 #include <string.h>
@@ -43,6 +46,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #ifdef __MINGW32__
 #define HAVE_GETPID 1
 #include <process.h>
+#include <_mingw.h> /* For __MINGW64_VERSION_MAJOR  */
 extern void random_r4 (GFC_REAL_4 *);
@@ -281,7 +285,7 @@ jump (xorshift1024star_state* rs)
 #define Q 127773 /* M / A (To avoid overflow on A * seed) */
 #define R 2836   /* M % A (To avoid overflow on A * seed) */
-static uint32_t
+__attribute__((unused)) static uint32_t
 lcg_parkmiller(uint32_t seed)
     uint32_t hi = seed / Q;
@@ -297,14 +301,21 @@ lcg_parkmiller(uint32_t seed)
 #undef Q
 #undef R
 /* Get some random bytes from the operating system in order to seed
    the PRNG.  */
 static int
 getosrandom (void *buf, size_t buflen)
-  /* TODO: On Windows one could use CryptGenRandom
+  /* rand_s is available in MinGW-w64 but not plain MinGW.  */
+  unsigned int* b = buf;
+  for (unsigned i = 0; i < buflen / sizeof (unsigned int); i++)
+    rand_s (&b[i]);
+  return buflen;
+  /*
      TODO: When glibc adds a wrapper for the getrandom() system call
      on Linux, one could use that.
@@ -333,12 +344,13 @@ getosrandom (void *buf, size_t buflen)
   seed ^= pid;
   uint32_t* ub = buf;
-  for (size_t i = 0; i < buflen; i++)
+  for (size_t i = 0; i < buflen / sizeof (uint32_t); i++)
       ub[i] = seed;
       seed = lcg_parkmiller (seed);
   return buflen;
+#endif /* __MINGW64_VERSION_MAJOR  */

Reply via email to