From: Mateusz Mikuła <mati...@gmail.com>

When using mkstemp, there is no guarantee nor expectation that the
caller has called srand() with an unique seed. Therefore, in practice,
many users of mkstemp run with the same seed (unseeded).

Normally, the implementation of mkstemp does handle collisions just
fine, by continuing iteration and trying another pseudorandom file
name, until finding a unique name. (If there are collisions and both
processes run unseeded, both will always try the same sequence though.)

However in some rare cases of collisions, _sopen can return an error,
setting errno to e.g. EACCES. In this case, our implementation of
mkstemp stops iterating and returns the error to the caller. (This is,
in general, the right decision; if the user does not have write
permission in the expected directory, we should abort, not keep retrying
infinitely.)

Use rand_s() to get properly unique random numbers here, without
relying on the caller seeding the random number generator.

Older versions of msvcrt.dll do lack rand_s, but in libmsvcrt-os.a,
we provide rand_s as a wrapper that tries to locate rand_s at runtime,
and tries to do a fallback implementation otherwise. If all the
fallbacks within our rand_s() wrapper fail, fall back on plain rand(),
which is no worse than what we had before.

The issue with collisions can be reproduced with these commands (run
them all in without long pauses):

for n in {1..15000}; do rm -f lib/libLLVMAVRAsmParser.a && \
ar qc lib/libLLVMAVRAsmParser.a 
lib/Target/AVR/AsmParser/CMakeFiles/LLVMAVRAsmParser.dir/AVRAsmParser.cpp.obj 
&& \
ranlib.exe lib/libLLVMAVRAsmParser.a; done &

for n in {1..15000}; do rm -f lib/libLLVMSparcCodeGen.a && \
ar qc lib/libLLVMSparcCodeGen.a 
lib/Target/Sparc/CMakeFiles/LLVMSparcCodeGen.dir/*.obj && \
ranlib.exe lib/libLLVMSparcCodeGen.a; done

echo "done"
fg

Before the patch it will fail with an error: "ranlib.exe: could not
create temporary file whilst writing archive: no more archived files"
or "...: Permission denied".

The changes in this patch were proposed by Josh Stone on Rust's Zulip
server and I was asked to forward it.

Co-Authored-By: Josh Stone <jist...@redhat.com>
Signed-off-by: Mateusz Mikuła <mati...@gmail.com>
Signed-off-by: Martin Storsjö <mar...@martin.st>
---
 mingw-w64-crt/misc/mkstemp.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/mingw-w64-crt/misc/mkstemp.c b/mingw-w64-crt/misc/mkstemp.c
index 6b327f2fc..3b6246540 100644
--- a/mingw-w64-crt/misc/mkstemp.c
+++ b/mingw-w64-crt/misc/mkstemp.c
@@ -1,3 +1,4 @@
+#define _CRT_RAND_S
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -25,6 +26,7 @@
 int __cdecl mkstemp (char *template_name)
 {
     int i, j, fd, len, index;
+    unsigned int r;
 
     /* These are the (62) characters used in temporary filenames. */
     static const char letters[] = 
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@@ -45,7 +47,9 @@ int __cdecl mkstemp (char *template_name)
      */
     for (i = 0; i >= 0; i++) {
         for(j = index; j < len; j++) {
-            template_name[j] = letters[rand () % 62];
+            if (rand_s(&r))
+                r = rand();
+            template_name[j] = letters[r % 62];
         }
         fd = _sopen(template_name,
                 _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
-- 
2.34.1



_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to