Subject: bug#57129: 29.0.50; Improve behavior of conditionals in Eshell

From: Paul Eggert <[email-masked]>
Date: Tue, 16 Aug 2022 12:11:24 -0700

On 8/16/22 10:47, Eli Zaretskii wrote:

> (Why are you talking about MS-DOS?)

I mistakenly thought it was an MS-DOS problem because tempname.c 
ordinarily would use clock_gettime on MinGW. I didn't know Emacs 
'configure' deliberately suppresses MinGW's clock_gettime.

> Thanks, but why not use 'random' instead?  Emacs does have it on all
> platforms, including MS-Windows.  AFAIU, it's better than 'rand'.

If the code used 'random' then the Gnulib 'tempname' module would need 
to add a dependency on the Gnulib 'random' module, which would in turn 
add a cascading dependency on Gnulib's 'random_r' module. It's better to 
avoid this dependency if we can easily do so.

Come to think of it, we don't need to use 'rand' either, since 
tempname.c already has a good-enough pseudorandom generator. I installed 
into Gnulib the attached patch, which I hope fixes the Emacs problem 
without changing glibc's generated code (once this gets migrated back 
into glibc).

>> If I understand things correctly this should make the names random
>> enough on MS-DOS, though Emacs itself still needs a patch as I mentioned
>> a few minutes ago.
> 
> Why would Emacs need that patch?

In another part of this thread you rejected that patch, on the grounds 
that fixing the unlikely Emacs bug is more trouble than it's worth. So 
I'll drop that suggestion.

From 512e44adaebb3096ddd1bf564e679d06e0301616 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Tue, 16 Aug 2022 12:06:48 -0700
Subject: [PATCH] tempname: generate better names for MinGW Emacs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

On MinGW, GNU Emacs disables clock_gettime, which reliably breaks
some of gen_tempname’s optimistic callers.  Work around the
problem by making the generated names less predictable.  We don’t
need cryptographic randomness here, just enough unpredictability
to keep Emacs happy most of the time.
* lib/tempname.c (HAS_CLOCK_ENTROPY): New macro.
(random_bits): Use it.
(try_tempname_len): On systems lacking clock entropy, maintain
state so that gen_filename generates less-predictable names on
successive successful calls.
---
 ChangeLog      | 14 ++++++++++++++
 lib/tempname.c | 18 +++++++++++++++++-
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index b639d1709d..eb96281591 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2022-08-16  Paul Eggert  <[email-masked]>
+
+	tempname: generate better names for MinGW Emacs
+	On MinGW, GNU Emacs disables clock_gettime, which reliably breaks
+	some of gen_tempname’s optimistic callers.  Work around the
+	problem by making the generated names less predictable.  We don’t
+	need cryptographic randomness here, just enough unpredictability
+	to keep Emacs happy most of the time.
+	* lib/tempname.c (HAS_CLOCK_ENTROPY): New macro.
+	(random_bits): Use it.
+	(try_tempname_len): On systems lacking clock entropy, maintain
+	state so that gen_filename generates less-predictable names on
+	successive successful calls.
+
 2022-08-16  Simon Josefsson  <[email-masked]>
 
 	maintainer-makefile: Check for incorrect DISTCHECK_CONFIGURE_FLAGS
diff --git a/lib/tempname.c b/lib/tempname.c
index e6520191d7..5adfe629a8 100644
--- a/lib/tempname.c
+++ b/lib/tempname.c
@@ -77,6 +77,12 @@ typedef uint_fast64_t random_value;
 #define BASE_62_DIGITS 10 /* 62**10 < UINT_FAST64_MAX */
 #define BASE_62_POWER (62LL * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62)
 
+#if _LIBC || (defined CLOCK_MONOTONIC && HAVE_CLOCK_GETTIME)
+# define HAS_CLOCK_ENTROPY true
+#else
+# define HAS_CLOCK_ENTROPY false
+#endif
+
 static random_value
 random_bits (random_value var, bool use_getrandom)
 {
@@ -84,7 +90,7 @@ random_bits (random_value var, bool use_getrandom)
   /* Without GRND_NONBLOCK it can be blocked for minutes on some systems.  */
   if (use_getrandom && __getrandom (&r, sizeof r, GRND_NONBLOCK) == sizeof r)
     return r;
-#if _LIBC || (defined CLOCK_MONOTONIC && HAVE_CLOCK_GETTIME)
+#if HAS_CLOCK_ENTROPY
   /* Add entropy if getrandom did not work.  */
   struct __timespec64 tv;
   __clock_gettime64 (CLOCK_MONOTONIC, &tv);
@@ -267,6 +273,13 @@ try_tempname_len (char *tmpl, int suffixlen, void *args,
      alignment.  */
   random_value v = ((uintptr_t) &v) / alignof (max_align_t);
 
+#if !HAS_CLOCK_ENTROPY
+  /* Arrange gen_tempname to return less predictable file names on
+     systems lacking clock entropy <https://bugs.gnu.org/57129>.  */
+  static random_value prev_v;
+  v ^= prev_v;
+#endif
+
   /* How many random base-62 digits can currently be extracted from V.  */
   int vdigits = 0;
 
@@ -318,6 +331,9 @@ try_tempname_len (char *tmpl, int suffixlen, void *args,
       if (fd >= 0)
         {
           __set_errno (save_errno);
+#if !HAS_CLOCK_ENTROPY
+          prev_v = v;
+#endif
           return fd;
         }
       else if (errno != EEXIST)
-- 
2.34.1