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