This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH, libgfortran] Use rand_s on MinGW-w64, fix bounds overflow
- From: Janne Blomqvist <blomqvist dot janne at gmail dot com>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>, Fortran List <fortran at gcc dot gnu dot org>
- Date: Wed, 21 Sep 2016 13:15:57 +0300
- Subject: [PATCH, libgfortran] Use rand_s on MinGW-w64, fix bounds overflow
- Authentication-results: sourceware.org; auth=none
Hi,
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
does.
Committed r240309 as obvious/lacking active GFortran windows maintainers.
2016-09-21 Janne Blomqvist <jb@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 */
#endif
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. */
+#ifdef __MINGW64_VERSION_MAJOR
+ unsigned int* b = buf;
+ for (unsigned i = 0; i < buflen / sizeof (unsigned int); i++)
+ rand_s (&b[i]);
+ return buflen;
+#else
+ /*
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;
#endif
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 */
}