GNU bug report logs - #15015
Fix some minor races in hosts lacking mkostemp

Previous Next

Package: emacs;

Reported by: Paul Eggert <eggert <at> cs.ucla.edu>

Date: Sat, 3 Aug 2013 08:29:02 UTC

Severity: normal

Tags: patch

Done: Paul Eggert <eggert <at> cs.ucla.edu>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 15015 in the body.
You can then email your comments to 15015 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#15015; Package emacs. (Sat, 03 Aug 2013 08:29:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Paul Eggert <eggert <at> cs.ucla.edu>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Sat, 03 Aug 2013 08:29:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: bug-emacs <bug-gnu-emacs <at> gnu.org>
Cc: Eli Zaretskii <eliz <at> gnu.org>
Subject: Fix some minor races in hosts lacking mkostemp
Date: Sat, 03 Aug 2013 00:40:05 -0700
Tags: patch

Here's a proposed patch to fix some minor races in hosts lacking mkostemp.
I've tested this on Fedora 17 and Solaris 9.  Eli recently wrote that he
didn't think it was feasible to close the races on Microsoft platforms,
so I'm posting this on bug-gnu-emacs first (with a CC: to Eli to give him
a heads-up).  It looks to me like it may close the races on Microsoft platforms,
at least if they support O_EXCL, and at any rate I hope it doesn't hurt
on those platforms.

Most of this patch consists of code copied automatically from Gnulib.
The meat of the patch is in src/callproc.c and src/filelock.c.

=== modified file 'ChangeLog'
--- ChangeLog	2013-07-29 11:35:16 +0000
+++ ChangeLog	2013-08-03 07:19:27 +0000
@@ -1,3 +1,12 @@
+2013-08-03  Paul Eggert  <eggert <at> cs.ucla.edu>
+
+	Fix some minor races in hosts lacking mkostemp.
+	Gnulib's emulation of mkostemp doesn't have races that Emacs's does.
+	* lib/mkostemp.c, lib/secure_getenv.c, lib/tempname.c, lib/tempname.h:
+	* m4/mkostemp.m4, m4/secure_getenv.m4, m4/tempname.m4:
+	New files, copied from Gnulib.
+	* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
+
 2013-07-29  Michael Albinus  <michael.albinus <at> gmx.de>
 
 	* INSTALL (DETAILED BUILDING AND INSTALLATION): Add

=== modified file 'admin/ChangeLog'
--- admin/ChangeLog	2013-07-12 06:45:04 +0000
+++ admin/ChangeLog	2013-08-03 07:19:27 +0000
@@ -1,3 +1,8 @@
+2013-08-03  Paul Eggert  <eggert <at> cs.ucla.edu>
+
+	Using Gnulib's mkostemp module.
+	* merge-gnulib (GNULIB_MODULES): Add mkostemp.
+
 2013-07-12  Glenn Morris  <rgm <at> gnu.org>
 
 	* admin.el (manual-style-string): Use non-abbreviated url.

=== modified file 'admin/merge-gnulib'
--- admin/merge-gnulib	2013-07-09 17:16:21 +0000
+++ admin/merge-gnulib	2013-08-03 07:19:27 +0000
@@ -32,7 +32,7 @@
   fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync
   getloadavg getopt-gnu gettime gettimeofday
   intprops largefile lstat
-  manywarnings memrchr mktime
+  manywarnings memrchr mkostemp mktime
   pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat
   sig2str socklen stat-time stdalign stdarg stdbool stdio
   strftime strtoimax strtoumax symlink sys_stat

=== modified file 'lib/gnulib.mk'
--- lib/gnulib.mk	2013-07-09 17:16:21 +0000
+++ lib/gnulib.mk	2013-08-03 07:19:27 +0000
@@ -21,7 +21,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday intprops largefile lstat manywarnings memrchr mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_tim
 e time ti
mer-time timespec-add timespec-sub unsetenv utimens warnings
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_sta
 t sys_tim
e time timer-time timespec-add timespec-sub unsetenv utimens warnings
 
 
 MOSTLYCLEANFILES += core *.stackdump
@@ -560,6 +560,15 @@
 
 ## end   gnulib module memrchr
 
+## begin gnulib module mkostemp
+
+
+EXTRA_DIST += mkostemp.c
+
+EXTRA_libgnu_a_SOURCES += mkostemp.c
+
+## end   gnulib module mkostemp
+
 ## begin gnulib module mktime
 
 
@@ -657,6 +666,17 @@
 
 ## end   gnulib module root-uid
 
+## begin gnulib module secure_getenv
+
+if gl_GNULIB_ENABLED_secure_getenv
+
+endif
+EXTRA_DIST += secure_getenv.c
+
+EXTRA_libgnu_a_SOURCES += secure_getenv.c
+
+## end   gnulib module secure_getenv
+
 ## begin gnulib module sig2str
 
 
@@ -1480,6 +1500,16 @@
 
 ## end   gnulib module sys_time
 
+## begin gnulib module tempname
+
+if gl_GNULIB_ENABLED_tempname
+libgnu_a_SOURCES += tempname.c
+
+endif
+EXTRA_DIST += tempname.h
+
+## end   gnulib module tempname
+
 ## begin gnulib module time
 
 BUILT_SOURCES += time.h

=== added file 'lib/mkostemp.c'
--- lib/mkostemp.c	1970-01-01 00:00:00 +0000
+++ lib/mkostemp.c	2013-08-03 07:19:27 +0000
@@ -0,0 +1,46 @@
+/* Copyright (C) 1998-1999, 2001, 2005-2007, 2009-2013 Free Software
+   Foundation, Inc.
+   This file is derived from the one in the GNU C Library.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#if !_LIBC
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#if !_LIBC
+# include "tempname.h"
+# define __gen_tempname gen_tempname
+# ifndef __GTFILE
+#  define __GT_FILE GT_FILE
+# endif
+#endif
+
+#include <stdio.h>
+
+#ifndef __GT_FILE
+# define __GT_FILE 0
+#endif
+
+/* Generate a unique temporary file name from XTEMPLATE.
+   The last six characters of XTEMPLATE must be "XXXXXX";
+   they are replaced with a string that makes the file name unique.
+   Then open the file and return a fd. */
+int
+mkostemp (char *xtemplate, int flags)
+{
+  return __gen_tempname (xtemplate, 0, flags, __GT_FILE);
+}

=== added file 'lib/secure_getenv.c'
--- lib/secure_getenv.c	1970-01-01 00:00:00 +0000
+++ lib/secure_getenv.c	2013-08-03 07:19:27 +0000
@@ -0,0 +1,41 @@
+/* Look up an environment variable more securely.
+
+   Copyright 2013 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#if !HAVE___SECURE_GETENV
+# if HAVE_ISSETUGID
+#  include <unistd.h>
+# else
+#  undef issetugid
+#  define issetugid() 1
+# endif
+#endif
+
+char *
+secure_getenv (char const *name)
+{
+#if HAVE___SECURE_GETENV
+  return __secure_getenv (name);
+#else
+  if (issetugid ())
+    return 0;
+  return getenv (name);
+#endif
+}

=== added file 'lib/tempname.c'
--- lib/tempname.c	1970-01-01 00:00:00 +0000
+++ lib/tempname.c	2013-08-03 07:19:27 +0000
@@ -0,0 +1,306 @@
+/* tempname.c - generate the name of a temporary file.
+
+   Copyright (C) 1991-2003, 2005-2007, 2009-2013 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Extracted from glibc sysdeps/posix/tempname.c.  See also tmpdir.c.  */
+
+#if !_LIBC
+# include <config.h>
+# include "tempname.h"
+#endif
+
+#include <sys/types.h>
+#include <assert.h>
+
+#include <errno.h>
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+#include <stdio.h>
+#ifndef P_tmpdir
+# define P_tmpdir "/tmp"
+#endif
+#ifndef TMP_MAX
+# define TMP_MAX 238328
+#endif
+#ifndef __GT_FILE
+# define __GT_FILE      0
+# define __GT_DIR       1
+# define __GT_NOCREATE  2
+#endif
+#if !_LIBC && (GT_FILE != __GT_FILE || GT_DIR != __GT_DIR       \
+               || GT_NOCREATE != __GT_NOCREATE)
+# error report this to bug-gnulib <at> gnu.org
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <sys/time.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
+
+#if _LIBC
+# define struct_stat64 struct stat64
+#else
+# define struct_stat64 struct stat
+# define __gen_tempname gen_tempname
+# define __getpid getpid
+# define __gettimeofday gettimeofday
+# define __mkdir mkdir
+# define __open open
+# define __lxstat64(version, file, buf) lstat (file, buf)
+# define __secure_getenv secure_getenv
+#endif
+
+#ifdef _LIBC
+# include <hp-timing.h>
+# if HP_TIMING_AVAIL
+#  define RANDOM_BITS(Var) \
+  if (__builtin_expect (value == UINT64_C (0), 0))                            \
+    {                                                                         \
+      /* If this is the first time this function is used initialize           \
+         the variable we accumulate the value in to some somewhat             \
+         random value.  If we'd not do this programs at startup time          \
+         might have a reduced set of possible names, at least on slow         \
+         machines.  */                                                        \
+      struct timeval tv;                                                      \
+      __gettimeofday (&tv, NULL);                                             \
+      value = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec;                      \
+    }                                                                         \
+  HP_TIMING_NOW (Var)
+# endif
+#endif
+
+/* Use the widest available unsigned type if uint64_t is not
+   available.  The algorithm below extracts a number less than 62**6
+   (approximately 2**35.725) from uint64_t, so ancient hosts where
+   uintmax_t is only 32 bits lose about 3.725 bits of randomness,
+   which is better than not having mkstemp at all.  */
+#if !defined UINT64_MAX && !defined uint64_t
+# define uint64_t uintmax_t
+#endif
+
+#if _LIBC
+/* Return nonzero if DIR is an existent directory.  */
+static int
+direxists (const char *dir)
+{
+  struct_stat64 buf;
+  return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode);
+}
+
+/* Path search algorithm, for tmpnam, tmpfile, etc.  If DIR is
+   non-null and exists, uses it; otherwise uses the first of $TMPDIR,
+   P_tmpdir, /tmp that exists.  Copies into TMPL a template suitable
+   for use with mk[s]temp.  Will fail (-1) if DIR is non-null and
+   doesn't exist, none of the searched dirs exists, or there's not
+   enough space in TMPL. */
+int
+__path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx,
+               int try_tmpdir)
+{
+  const char *d;
+  size_t dlen, plen;
+
+  if (!pfx || !pfx[0])
+    {
+      pfx = "file";
+      plen = 4;
+    }
+  else
+    {
+      plen = strlen (pfx);
+      if (plen > 5)
+        plen = 5;
+    }
+
+  if (try_tmpdir)
+    {
+      d = __secure_getenv ("TMPDIR");
+      if (d != NULL && direxists (d))
+        dir = d;
+      else if (dir != NULL && direxists (dir))
+        /* nothing */ ;
+      else
+        dir = NULL;
+    }
+  if (dir == NULL)
+    {
+      if (direxists (P_tmpdir))
+        dir = P_tmpdir;
+      else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))
+        dir = "/tmp";
+      else
+        {
+          __set_errno (ENOENT);
+          return -1;
+        }
+    }
+
+  dlen = strlen (dir);
+  while (dlen > 1 && dir[dlen - 1] == '/')
+    dlen--;                     /* remove trailing slashes */
+
+  /* check we have room for "${dir}/${pfx}XXXXXX\0" */
+  if (tmpl_len < dlen + 1 + plen + 6 + 1)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx);
+  return 0;
+}
+#endif /* _LIBC */
+
+/* These are the characters used in temporary file names.  */
+static const char letters[] =
+"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+/* Generate a temporary file name based on TMPL.  TMPL must match the
+   rules for mk[s]temp (i.e. end in "XXXXXX", possibly with a suffix).
+   The name constructed does not exist at the time of the call to
+   __gen_tempname.  TMPL is overwritten with the result.
+
+   KIND may be one of:
+   __GT_NOCREATE:       simply verify that the name does not exist
+                        at the time of the call.
+   __GT_FILE:           create the file using open(O_CREAT|O_EXCL)
+                        and return a read-write fd.  The file is mode 0600.
+   __GT_DIR:            create a directory, which will be mode 0700.
+
+   We use a clever algorithm to get hard-to-predict names. */
+int
+__gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
+{
+  int len;
+  char *XXXXXX;
+  static uint64_t value;
+  uint64_t random_time_bits;
+  unsigned int count;
+  int fd = -1;
+  int save_errno = errno;
+  struct_stat64 st;
+
+  /* A lower bound on the number of temporary files to attempt to
+     generate.  The maximum total number of temporary file names that
+     can exist for a given template is 62**6.  It should never be
+     necessary to try all of these combinations.  Instead if a reasonable
+     number of names is tried (we define reasonable as 62**3) fail to
+     give the system administrator the chance to remove the problems.  */
+#define ATTEMPTS_MIN (62 * 62 * 62)
+
+  /* The number of times to attempt to generate a temporary file.  To
+     conform to POSIX, this must be no smaller than TMP_MAX.  */
+#if ATTEMPTS_MIN < TMP_MAX
+  unsigned int attempts = TMP_MAX;
+#else
+  unsigned int attempts = ATTEMPTS_MIN;
+#endif
+
+  len = strlen (tmpl);
+  if (len < 6 + suffixlen || memcmp (&tmpl[len - 6 - suffixlen], "XXXXXX", 6))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  /* This is where the Xs start.  */
+  XXXXXX = &tmpl[len - 6 - suffixlen];
+
+  /* Get some more or less random data.  */
+#ifdef RANDOM_BITS
+  RANDOM_BITS (random_time_bits);
+#else
+  {
+    struct timeval tv;
+    __gettimeofday (&tv, NULL);
+    random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec;
+  }
+#endif
+  value += random_time_bits ^ __getpid ();
+
+  for (count = 0; count < attempts; value += 7777, ++count)
+    {
+      uint64_t v = value;
+
+      /* Fill in the random bits.  */
+      XXXXXX[0] = letters[v % 62];
+      v /= 62;
+      XXXXXX[1] = letters[v % 62];
+      v /= 62;
+      XXXXXX[2] = letters[v % 62];
+      v /= 62;
+      XXXXXX[3] = letters[v % 62];
+      v /= 62;
+      XXXXXX[4] = letters[v % 62];
+      v /= 62;
+      XXXXXX[5] = letters[v % 62];
+
+      switch (kind)
+        {
+        case __GT_FILE:
+          fd = __open (tmpl,
+                       (flags & ~O_ACCMODE)
+                       | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+          break;
+
+        case __GT_DIR:
+          fd = __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR);
+          break;
+
+        case __GT_NOCREATE:
+          /* This case is backward from the other three.  __gen_tempname
+             succeeds if __xstat fails because the name does not exist.
+             Note the continue to bypass the common logic at the bottom
+             of the loop.  */
+          if (__lxstat64 (_STAT_VER, tmpl, &st) < 0)
+            {
+              if (errno == ENOENT)
+                {
+                  __set_errno (save_errno);
+                  return 0;
+                }
+              else
+                /* Give up now. */
+                return -1;
+            }
+          continue;
+
+        default:
+          assert (! "invalid KIND in __gen_tempname");
+          abort ();
+        }
+
+      if (fd >= 0)
+        {
+          __set_errno (save_errno);
+          return fd;
+        }
+      else if (errno != EEXIST)
+        return -1;
+    }
+
+  /* We got out of the loop because we ran out of combinations to try.  */
+  __set_errno (EEXIST);
+  return -1;
+}

=== added file 'lib/tempname.h'
--- lib/tempname.h	1970-01-01 00:00:00 +0000
+++ lib/tempname.h	2013-08-03 07:19:27 +0000
@@ -0,0 +1,50 @@
+/* Create a temporary file or directory.
+
+   Copyright (C) 2006, 2009-2013 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* header written by Eric Blake */
+
+#ifndef GL_TEMPNAME_H
+# define GL_TEMPNAME_H
+
+# include <stdio.h>
+
+# ifdef __GT_FILE
+#  define GT_FILE     __GT_FILE
+#  define GT_DIR      __GT_DIR
+#  define GT_NOCREATE __GT_NOCREATE
+# else
+#  define GT_FILE     0
+#  define GT_DIR      1
+#  define GT_NOCREATE 2
+# endif
+
+/* Generate a temporary file name based on TMPL.  TMPL must match the
+   rules for mk[s]temp (i.e. end in "XXXXXX", possibly with a suffix).
+   The name constructed does not exist at the time of the call to
+   gen_tempname.  TMPL is overwritten with the result.
+
+   KIND may be one of:
+   GT_NOCREATE:         simply verify that the name does not exist
+                        at the time of the call.
+   GT_FILE:             create a large file using open(O_CREAT|O_EXCL)
+                        and return a read-write fd.  The file is mode 0600.
+   GT_DIR:              create a directory, which will be mode 0700.
+
+   We use a clever algorithm to get hard-to-predict names. */
+extern int gen_tempname (char *tmpl, int suffixlen, int flags, int kind);
+
+#endif /* GL_TEMPNAME_H */

=== modified file 'm4/gnulib-comp.m4'
--- m4/gnulib-comp.m4	2013-07-09 17:16:21 +0000
+++ m4/gnulib-comp.m4	2013-08-03 07:19:27 +0000
@@ -89,6 +89,7 @@
   # Code from module lstat:
   # Code from module manywarnings:
   # Code from module memrchr:
+  # Code from module mkostemp:
   # Code from module mktime:
   # Code from module multiarch:
   # Code from module nocrash:
@@ -102,6 +103,7 @@
   # Code from module readlink:
   # Code from module readlinkat:
   # Code from module root-uid:
+  # Code from module secure_getenv:
   # Code from module sig2str:
   # Code from module signal-h:
   # Code from module snippet/_Noreturn:
@@ -134,6 +136,7 @@
   # Code from module sys_select:
   # Code from module sys_stat:
   # Code from module sys_time:
+  # Code from module tempname:
   # Code from module time:
   # Code from module time_r:
   # Code from module timer-time:
@@ -274,6 +277,13 @@
     gl_PREREQ_MEMRCHR
   fi
   gl_STRING_MODULE_INDICATOR([memrchr])
+  gl_FUNC_MKOSTEMP
+  if test $HAVE_MKOSTEMP = 0; then
+    AC_LIBOBJ([mkostemp])
+    gl_PREREQ_MKOSTEMP
+  fi
+  gl_MODULE_INDICATOR([mkostemp])
+  gl_STDLIB_MODULE_INDICATOR([mkostemp])
   gl_FUNC_MKTIME
   if test $REPLACE_MKTIME = 1; then
     AC_LIBOBJ([mktime])
@@ -381,9 +391,11 @@
   gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7=false
   gl_gnulib_enabled_pathmax=false
   gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false
+  gl_gnulib_enabled_secure_getenv=false
   gl_gnulib_enabled_stat=false
   gl_gnulib_enabled_strtoll=false
   gl_gnulib_enabled_strtoull=false
+  gl_gnulib_enabled_tempname=false
   gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false
   func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b ()
   {
@@ -485,6 +497,18 @@
       gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=true
     fi
   }
+  func_gl_gnulib_m4code_secure_getenv ()
+  {
+    if ! $gl_gnulib_enabled_secure_getenv; then
+      gl_FUNC_SECURE_GETENV
+      if test $HAVE_SECURE_GETENV = 0; then
+        AC_LIBOBJ([secure_getenv])
+        gl_PREREQ_SECURE_GETENV
+      fi
+      gl_STDLIB_MODULE_INDICATOR([secure_getenv])
+      gl_gnulib_enabled_secure_getenv=true
+    fi
+  }
   func_gl_gnulib_m4code_stat ()
   {
     if ! $gl_gnulib_enabled_stat; then
@@ -527,6 +551,14 @@
       gl_gnulib_enabled_strtoull=true
     fi
   }
+  func_gl_gnulib_m4code_tempname ()
+  {
+    if ! $gl_gnulib_enabled_tempname; then
+      gl_FUNC_GEN_TEMPNAME
+      gl_gnulib_enabled_tempname=true
+      func_gl_gnulib_m4code_secure_getenv
+    fi
+  }
   func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec ()
   {
     if ! $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then
@@ -569,6 +601,9 @@
   if test $REPLACE_LSTAT = 1; then
     func_gl_gnulib_m4code_stat
   fi
+  if test $HAVE_MKOSTEMP = 0; then
+    func_gl_gnulib_m4code_tempname
+  fi
   if test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1; then
     func_gl_gnulib_m4code_stat
   fi
@@ -598,9 +633,11 @@
   AM_CONDITIONAL([gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7], [$gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_pathmax], [$gl_gnulib_enabled_pathmax])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], [$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c])
+  AM_CONDITIONAL([gl_GNULIB_ENABLED_secure_getenv], [$gl_gnulib_enabled_secure_getenv])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_stat], [$gl_gnulib_enabled_stat])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoull], [$gl_gnulib_enabled_strtoull])
+  AM_CONDITIONAL([gl_GNULIB_ENABLED_tempname], [$gl_gnulib_enabled_tempname])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], [$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec])
   # End of code from modules
   m4_ifval(gl_LIBSOURCES_LIST, [
@@ -806,6 +843,7 @@
   lib/md5.c
   lib/md5.h
   lib/memrchr.c
+  lib/mkostemp.c
   lib/mktime-internal.h
   lib/mktime.c
   lib/openat-priv.h
@@ -821,6 +859,7 @@
   lib/readlink.c
   lib/readlinkat.c
   lib/root-uid.h
+  lib/secure_getenv.c
   lib/sha1.c
   lib/sha1.h
   lib/sha256.c
@@ -853,6 +892,8 @@
   lib/sys_select.in.h
   lib/sys_stat.in.h
   lib/sys_time.in.h
+  lib/tempname.c
+  lib/tempname.h
   lib/time.in.h
   lib/time_r.c
   lib/timespec-add.c
@@ -908,6 +949,7 @@
   m4/manywarnings.m4
   m4/md5.m4
   m4/memrchr.m4
+  m4/mkostemp.m4
   m4/mktime.m4
   m4/multiarch.m4
   m4/nocrash.m4
@@ -919,6 +961,7 @@
   m4/putenv.m4
   m4/readlink.m4
   m4/readlinkat.m4
+  m4/secure_getenv.m4
   m4/setenv.m4
   m4/sha1.m4
   m4/sha256.m4
@@ -948,6 +991,7 @@
   m4/sys_socket_h.m4
   m4/sys_stat_h.m4
   m4/sys_time_h.m4
+  m4/tempname.m4
   m4/time_h.m4
   m4/time_r.m4
   m4/timer_time.m4

=== added file 'm4/mkostemp.m4'
--- m4/mkostemp.m4	1970-01-01 00:00:00 +0000
+++ m4/mkostemp.m4	2013-08-03 07:19:27 +0000
@@ -0,0 +1,23 @@
+# mkostemp.m4 serial 2
+dnl Copyright (C) 2009-2013 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_MKOSTEMP],
+[
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+
+  dnl Persuade glibc <stdlib.h> to declare mkostemp().
+  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+  AC_CHECK_FUNCS_ONCE([mkostemp])
+  if test $ac_cv_func_mkostemp != yes; then
+    HAVE_MKOSTEMP=0
+  fi
+])
+
+# Prerequisites of lib/mkostemp.c.
+AC_DEFUN([gl_PREREQ_MKOSTEMP],
+[
+])

=== added file 'm4/secure_getenv.m4'
--- m4/secure_getenv.m4	1970-01-01 00:00:00 +0000
+++ m4/secure_getenv.m4	2013-08-03 07:19:27 +0000
@@ -0,0 +1,25 @@
+# Look up an environment variable more securely.
+dnl Copyright 2013 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_SECURE_GETENV],
+[
+  dnl Persuade glibc <stdlib.h> to declare secure_getenv().
+  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  AC_CHECK_FUNCS_ONCE([secure_getenv])
+  if test $ac_cv_func_secure_getenv = no; then
+    HAVE_SECURE_GETENV=0
+  fi
+])
+
+# Prerequisites of lib/secure_getenv.c.
+AC_DEFUN([gl_PREREQ_SECURE_GETENV], [
+  AC_CHECK_FUNCS([__secure_getenv])
+  if test $ac_cv_func___secure_getenv = no; then
+    AC_CHECK_FUNCS([issetugid])
+  fi
+])

=== added file 'm4/tempname.m4'
--- m4/tempname.m4	1970-01-01 00:00:00 +0000
+++ m4/tempname.m4	2013-08-03 07:19:27 +0000
@@ -0,0 +1,19 @@
+#serial 5
+
+# Copyright (C) 2006-2007, 2009-2013 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# glibc provides __gen_tempname as a wrapper for mk[ds]temp.  Expose
+# it as a public API, and provide it on systems that are lacking.
+AC_DEFUN([gl_FUNC_GEN_TEMPNAME],
+[
+  gl_PREREQ_TEMPNAME
+])
+
+# Prerequisites of lib/tempname.c.
+AC_DEFUN([gl_PREREQ_TEMPNAME],
+[
+  :
+])

=== modified file 'src/ChangeLog'
--- src/ChangeLog	2013-08-03 03:29:03 +0000
+++ src/ChangeLog	2013-08-03 07:19:27 +0000
@@ -1,3 +1,10 @@
+2013-08-03  Paul Eggert  <eggert <at> cs.ucla.edu>
+
+	Fix some minor races in hosts lacking mkostemp.
+	* callproc.c (create_temp_file):
+	* filelock.c (create_lock_file):
+	Assume mkostemp, since it's now provided by Gnulib.
+
 2013-08-03  Dmitry Antipov  <dmantipov <at> yandex.ru>
 
 	Drop FRAME_PTR typedef.

=== modified file 'src/callproc.c'
--- src/callproc.c	2013-07-30 21:44:43 +0000
+++ src/callproc.c	2013-08-03 07:19:27 +0000
@@ -1009,23 +1009,11 @@
     tempfile = SSDATA (filename_string);
 
     {
-      int fd;
-
-#ifdef HAVE_MKOSTEMP
-      fd = mkostemp (tempfile, O_CLOEXEC);
-#elif defined HAVE_MKSTEMP
-      fd = mkstemp (tempfile);
-#else
-      errno = EEXIST;
-      mktemp (tempfile);
-      fd = *tempfile ? 0 : -1;
-#endif
+      int fd = mkostemp (tempfile, O_CLOEXEC);
       if (fd < 0)
 	report_file_error ("Failed to open temporary file using pattern",
 			   pattern);
-#if defined HAVE_MKOSTEMP || defined HAVE_MKSTEMP
       emacs_close (fd);
-#endif
     }
 
     record_unwind_protect (delete_temp_file, filename_string);

=== modified file 'src/filelock.c'
--- src/filelock.c	2013-07-19 18:09:23 +0000
+++ src/filelock.c	2013-08-03 07:35:27 +0000
@@ -411,28 +411,14 @@
       memcpy (nonce, lfname, lfdirlen);
       strcpy (nonce + lfdirlen, nonce_base);
 
-#if HAVE_MKOSTEMP
-      /* Prefer mkostemp to mkstemp, as it avoids a window where FD is
-	 temporarily open without close-on-exec.  */
       fd = mkostemp (nonce, O_BINARY | O_CLOEXEC);
-#elif HAVE_MKSTEMP
-      /* Prefer mkstemp to mktemp, as it avoids a race between
-	 mktemp and emacs_open.  */
-      fd = mkstemp (nonce);
-#else
-      mktemp (nonce);
-      fd = emacs_open (nonce, O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
-		       S_IRUSR | S_IWUSR);
-#endif
-
       if (fd < 0)
 	err = errno;
       else
 	{
 	  ptrdiff_t lock_info_len;
-#if ! (HAVE_MKOSTEMP && O_CLOEXEC)
-	  fcntl (fd, F_SETFD, FD_CLOEXEC);
-#endif
+	  if (! O_CLOEXEC)
+	    fcntl (fd, F_SETFD, FD_CLOEXEC);
 	  lock_info_len = strlen (lock_info_str);
 	  err = 0;
 	  /* Use 'write', not 'emacs_write', as garbage collection





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#15015; Package emacs. (Sat, 03 Aug 2013 08:39:01 GMT) Full text and rfc822 format available.

Message #8 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Paul Eggert <eggert <at> cs.ucla.edu>
Cc: bug-gnu-emacs <at> gnu.org
Subject: Re: Fix some minor races in hosts lacking mkostemp
Date: Sat, 03 Aug 2013 11:38:03 +0300
> Date: Sat, 03 Aug 2013 00:40:05 -0700
> From: Paul Eggert <eggert <at> cs.ucla.edu>
> CC: Eli Zaretskii <eliz <at> gnu.org>
> 
> Here's a proposed patch to fix some minor races in hosts lacking mkostemp.
> I've tested this on Fedora 17 and Solaris 9.  Eli recently wrote that he
> didn't think it was feasible to close the races on Microsoft platforms,
> so I'm posting this on bug-gnu-emacs first (with a CC: to Eli to give him
> a heads-up).  It looks to me like it may close the races on Microsoft platforms,
> at least if they support O_EXCL, and at any rate I hope it doesn't hurt
> on those platforms.
> 
> Most of this patch consists of code copied automatically from Gnulib.
> The meat of the patch is in src/callproc.c and src/filelock.c.

Thanks.  However, I'm reluctant to use the gnulib mkostemp module,
because it relies on quite a few functions that are redefined in
Emacs, and I have no idea what will this do to the gnulib
implementation.  Also, since we still didn't remove the support for
MS-Windows builds that use nt/configure.bat and the makefile-w32.in
files, the uses of mktemp in the Emacs sources should be left alone
for now, if we go this route.

I thought of a far easier solution: use the same code as sys_mktemp
does, but use 'open' or '_sopen' instead of faccessat.  I think this
will solve the problem much more locally and with much smaller impact.
If you agree, I will work on providing 'mkostemp' for w32.

In any case, we cannot just remove the other alternatives; at least
for the MSDOS build we need to keep the HAVE_MKSTEMP version.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#15015; Package emacs. (Sat, 03 Aug 2013 09:03:02 GMT) Full text and rfc822 format available.

Message #11 received at 15015 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: eggert <at> cs.ucla.edu
Cc: 15015 <at> debbugs.gnu.org
Subject: Re: bug#15015: Fix some minor races in hosts lacking mkostemp
Date: Sat, 03 Aug 2013 12:02:37 +0300
> Date: Sat, 03 Aug 2013 11:38:03 +0300
> From: Eli Zaretskii <eliz <at> gnu.org>
> Cc: 15015 <at> debbugs.gnu.org
> 
> In any case, we cannot just remove the other alternatives; at least
> for the MSDOS build we need to keep the HAVE_MKSTEMP version.

Of course, alternatively, we could add an implementation of 'mkostemp'
in msdos.c.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#15015; Package emacs. (Sat, 03 Aug 2013 14:41:03 GMT) Full text and rfc822 format available.

Message #14 received at 15015 <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 15015 <at> debbugs.gnu.org
Subject: Re: bug#15015: Fix some minor races in hosts lacking mkostemp
Date: Sat, 03 Aug 2013 07:40:35 -0700
On 08/03/2013 01:38 AM, Eli Zaretskii wrote:

> the gnulib mkostemp module ... relies on quite a few functions that are
> redefined in Emacs, and I have no idea what will this do to the gnulib
> implementation.

I don't see the problem; could you please explain further?
On Microsoft platforms, the only functions that the mkostemp
module should use should be getenv, strlen, memcmp,
gettimeofday, open (..., O_RDWR | O_CREAT | O_EXCL, S_IRUSR
| S_IWUSR), and lstat, and this sort of thing is already
working elsewhere.  mkostemp calls mkdir but that call is
never used by Emacs so as long as it compiles we should be
OK.

> Also, since we still didn't remove the support for
> MS-Windows builds that use nt/configure.bat and the makefile-w32.in
> files, the uses of mktemp in the Emacs sources should be left alone
> for now, if we go this route.

Presumably nt/configure.bat and makefile-w32.in could be updated
to compile the new files.  This sort of thing should be routine,
if that avenue is still supported.

> I thought of a far easier solution: use the same code as sys_mktemp
> does, but use 'open' or '_sopen' instead of faccessat.

This won't suffice for POSIXish platforms that lack mkostemp
but have 'open' with O_EXCL.  Solaris is one example.  The
Gnulib mkostemp module fixes the races on those platforms.

> alternatively, we could add an implementation of 'mkostemp'
> in msdos.c.

Sure, that should work fine.  The MS-DOS port need not compile
the new lib/*.c files.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#15015; Package emacs. (Sat, 03 Aug 2013 14:56:02 GMT) Full text and rfc822 format available.

Message #17 received at 15015 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Paul Eggert <eggert <at> cs.ucla.edu>
Cc: 15015 <at> debbugs.gnu.org
Subject: Re: bug#15015: Fix some minor races in hosts lacking mkostemp
Date: Sat, 03 Aug 2013 17:55:19 +0300
> Date: Sat, 03 Aug 2013 07:40:35 -0700
> From: Paul Eggert <eggert <at> cs.ucla.edu>
> CC: 15015 <at> debbugs.gnu.org
> 
> On 08/03/2013 01:38 AM, Eli Zaretskii wrote:
> 
> > the gnulib mkostemp module ... relies on quite a few functions that are
> > redefined in Emacs, and I have no idea what will this do to the gnulib
> > implementation.
> 
> I don't see the problem; could you please explain further?
> On Microsoft platforms, the only functions that the mkostemp
> module should use should be getenv, strlen, memcmp,
> gettimeofday, open (..., O_RDWR | O_CREAT | O_EXCL, S_IRUSR
> | S_IWUSR), and lstat, and this sort of thing is already
> working elsewhere.

gettimeofday, open, and lstat are implemented by Emacs in w32.c.  At
lest the last 2 are not equivalent to what gnulib uses.

> > Also, since we still didn't remove the support for
> > MS-Windows builds that use nt/configure.bat and the makefile-w32.in
> > files, the uses of mktemp in the Emacs sources should be left alone
> > for now, if we go this route.
> 
> Presumably nt/configure.bat and makefile-w32.in could be updated
> to compile the new files.  This sort of thing should be routine,
> if that avenue is still supported.

This "support" needs volunteers, which didn't yet show up.  But if
there are two alternatives to fix a problem, and one of them breaks
this "support" while the other doesn't, I'd prefer the latter.

> > I thought of a far easier solution: use the same code as sys_mktemp
> > does, but use 'open' or '_sopen' instead of faccessat.
> 
> This won't suffice for POSIXish platforms that lack mkostemp
> but have 'open' with O_EXCL.  Solaris is one example.  The
> Gnulib mkostemp module fixes the races on those platforms.

That's OK.  We can always install the gnulib stuff for those other
platforms, and work around it on Windows.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#15015; Package emacs. (Sat, 03 Aug 2013 21:27:02 GMT) Full text and rfc822 format available.

Message #20 received at 15015 <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 15015 <at> debbugs.gnu.org
Subject: Re: bug#15015: Fix some minor races in hosts lacking mkostemp
Date: Sat, 03 Aug 2013 14:26:20 -0700
On 08/03/2013 07:55 AM, Eli Zaretskii wrote:

> gettimeofday, open, and lstat are implemented by Emacs in w32.c.  At
> lest the last 2 are not equivalent to what gnulib uses.

The lack of equivalence shouldn't matter.  The lstat call
(though it is compiled) won't be used by Emacs's use of the
mkostemp module on Microsoft platforms, so it's OK.  
mkostemp always calls 'open' with O_CREAT | O_EXCL; in that
case sys_open is just a simple wrapper around _open, so that
should be OK too.  And gettimeofday, as you mentioned, isn't
a problem.

>> Presumably nt/configure.bat and makefile-w32.in could be updated
>> to compile the new files.  This sort of thing should be routine,
>> if that avenue is still supported.
>
> This "support" needs volunteers, which didn't yet show up.

If nobody's supporting it, then it's not really supported.
It's not a big deal -- if someone wants to start supporting
that build mechanism again, it'd be an easy-enough task.
In the meantime we needn't let a deprecated and
apparently-unsupported build mechanism get in the way of
fixing bugs in mainstream builds.

> We can always install the gnulib stuff for those other platforms

Yes, that's a given.  We need to do that, to fix the race
condition bugs in OS X, Solaris, etc.

> and work around it on Windows.

I'm trying to help save work in the Windows port, by having
Windows Emacs use Gnulib mkostemp (which will be in the
source code anyway) the same way it's being used on OS X etc.
If this approach is feasible, it should save us all some
work; if not, it should be easy for a Windows expert to work
around any problems in w32.c and/or msdos.c.





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#15015; Package emacs. (Sun, 04 Aug 2013 15:45:01 GMT) Full text and rfc822 format available.

Message #23 received at 15015 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Paul Eggert <eggert <at> cs.ucla.edu>
Cc: 15015 <at> debbugs.gnu.org
Subject: Re: bug#15015: Fix some minor races in hosts lacking mkostemp
Date: Sun, 04 Aug 2013 18:44:24 +0300
> Date: Sat, 03 Aug 2013 14:26:20 -0700
> From: Paul Eggert <eggert <at> cs.ucla.edu>
> CC: 15015 <at> debbugs.gnu.org
> 
> On 08/03/2013 07:55 AM, Eli Zaretskii wrote:
> 
> > gettimeofday, open, and lstat are implemented by Emacs in w32.c.  At
> > lest the last 2 are not equivalent to what gnulib uses.
> 
> The lack of equivalence shouldn't matter.  The lstat call
> (though it is compiled) won't be used by Emacs's use of the
> mkostemp module on Microsoft platforms, so it's OK.  
> mkostemp always calls 'open' with O_CREAT | O_EXCL; in that
> case sys_open is just a simple wrapper around _open, so that
> should be OK too.  And gettimeofday, as you mentioned, isn't
> a problem.

I think sys_open also sets the no-inherit flag, so it's not just a
wrapper.

In any case, even if you are right (and I don't have enough resources
at the moment to verify that), reusing most of the code of sys_mktemp
to implement mkostemp seems like a safer bet, since that code is
already well tested by years of usage.  This also has the nice benefit
of not breaking the old configure.bat build.

So I went ahead and implemented mkostemp for MS-Windows (trunk
revision 113687).  I also removed sys_mktemp, as it is no longer
needed.

> >> Presumably nt/configure.bat and makefile-w32.in could be updated
> >> to compile the new files.  This sort of thing should be routine,
> >> if that avenue is still supported.
> >
> > This "support" needs volunteers, which didn't yet show up.
> 
> If nobody's supporting it, then it's not really supported.

That's true, but I'd like to avoid breaking it for as long as is
feasible, to let people adapt.

> > We can always install the gnulib stuff for those other platforms
> 
> Yes, that's a given.  We need to do that, to fix the race
> condition bugs in OS X, Solaris, etc.

Please go ahead.

> > and work around it on Windows.
> 
> I'm trying to help save work in the Windows port, by having
> Windows Emacs use Gnulib mkostemp (which will be in the
> source code anyway) the same way it's being used on OS X etc.
> If this approach is feasible, it should save us all some
> work; if not, it should be easy for a Windows expert to work
> around any problems in w32.c and/or msdos.c.

This approach is generally feasible, and I appreciate your efforts.
It's just that in this case having a Windows-specific implementation
was easy.

(Don't worry about msdos.c, I will fix that when I have time.  There
can be no race conditions on MSDOS anyway...)

Thanks.




Reply sent to Paul Eggert <eggert <at> cs.ucla.edu>:
You have taken responsibility. (Sun, 04 Aug 2013 17:02:02 GMT) Full text and rfc822 format available.

Notification sent to Paul Eggert <eggert <at> cs.ucla.edu>:
bug acknowledged by developer. (Sun, 04 Aug 2013 17:02:05 GMT) Full text and rfc822 format available.

Message #28 received at 15015-done <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 15015-done <at> debbugs.gnu.org
Subject: Re: bug#15015: Fix some minor races in hosts lacking mkostemp
Date: Sun, 04 Aug 2013 10:01:42 -0700
On 08/04/2013 08:44 AM, Eli Zaretskii wrote:
> So I went ahead and implemented mkostemp for MS-Windows (trunk
> revision 113687).  I also removed sys_mktemp, as it is no longer
> needed.

Thanks, that should do it on the Microsoft side.  I installed
the patch and am marking this done.  The patch I installed
also included the following additional simplification:

=== modified file 'ChangeLog'
--- ChangeLog	2013-08-04 01:23:59 +0000
+++ ChangeLog	2013-08-04 16:52:55 +0000
@@ -2,6 +2,9 @@
 
 	Fix some minor races in hosts lacking mkostemp (Bug#15015).
 	Gnulib's emulation of mkostemp doesn't have races that Emacs's does.
+	* configure.ac (mkostemp): Remove check for this function;
+	gnulib does the check now.
+	(mkstemp): Remove check for this no-longer-used function.
 	* lib/mkostemp.c, lib/secure_getenv.c, lib/tempname.c, lib/tempname.h:
 	* m4/mkostemp.m4, m4/secure_getenv.m4, m4/tempname.m4:
 	New files, copied from Gnulib.

=== modified file 'configure.ac'
--- configure.ac	2013-07-27 01:18:21 +0000
+++ configure.ac	2013-08-04 16:52:25 +0000
@@ -3277,7 +3277,7 @@
 getrlimit setrlimit shutdown getaddrinfo \
 strsignal setitimer \
 sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \
-gai_strerror mkostemp mkstemp getline getdelim sync \
+gai_strerror getline getdelim sync \
 difftime posix_memalign \
 getpwent endpwent getgrent endgrent \
 touchlock \

=== modified file 'lib-src/ChangeLog'
--- lib-src/ChangeLog	2013-07-10 23:23:57 +0000
+++ lib-src/ChangeLog	2013-08-04 16:48:02 +0000
@@ -1,3 +1,12 @@
+2013-08-04  Paul Eggert  <eggert <at> cs.ucla.edu>
+
+	Fix some minor races in hosts lacking mkostemp (Bug#15015).
+	* movemail.c (main):
+	* update-game-score.c (write_scores):
+	Use mkostemp (which now works on all platforms, due to changes
+	in the portability layer) rather than mktemp (which has a race)
+	or mkstemp (which we no longer bother with).
+
 2013-07-10  Paul Eggert  <eggert <at> cs.ucla.edu>
 
 	Port to C89.

=== modified file 'lib-src/movemail.c'
--- lib-src/movemail.c	2013-03-13 18:42:22 +0000
+++ lib-src/movemail.c	2013-08-04 16:35:45 +0000
@@ -304,24 +304,13 @@
 
 	  memcpy (tempname, inname, inname_dirlen);
 	  strcpy (tempname + inname_dirlen, "EXXXXXX");
-#ifdef HAVE_MKSTEMP
-	  desc = mkstemp (tempname);
-#else
-	  mktemp (tempname);
-	  if (!*tempname)
-	    desc = -1;
-	  else
-	    {
-	      unlink (tempname);
-	      desc = open (tempname, O_WRONLY | O_CREAT | O_EXCL, 0600);
-	    }
-#endif
+	  desc = mkostemp (tempname, 0);
 	  if (desc < 0)
 	    {
-	      int mkstemp_errno = errno;
+	      int mkostemp_errno = errno;
 	      error ("error while creating what would become the lock file",
 		     0, 0);
-	      errno = mkstemp_errno;
+	      errno = mkostemp_errno;
 	      pfatal_with_name (tempname);
 	    }
 	  close (desc);

=== modified file 'lib-src/update-game-score.c'
--- lib-src/update-game-score.c	2013-03-30 17:00:51 +0000
+++ lib-src/update-game-score.c	2013-08-04 16:28:47 +0000
@@ -383,6 +383,7 @@
 static int
 write_scores (const char *filename, const struct score_entry *scores, int count)
 {
+  int fd;
   FILE *f;
   int i;
   char *tempfile = malloc (strlen (filename) + strlen (".tempXXXXXX") + 1);
@@ -390,12 +391,11 @@
     return -1;
   strcpy (tempfile, filename);
   strcat (tempfile, ".tempXXXXXX");
-#ifdef HAVE_MKSTEMP
-  if (mkstemp (tempfile) < 0
-#else
-  if (mktemp (tempfile) != tempfile
-#endif
-      || !(f = fopen (tempfile, "w")))
+  fd = mkostemp (tempfile, 0);
+  if (fd < 0)
+    return -1;
+  f = fdopen (fd, "w");
+  if (! f)
     return -1;
   for (i = 0; i < count; i++)
     if (fprintf (f, "%ld %s %s\n", scores[i].score, scores[i].username,






bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Mon, 02 Sep 2013 11:24:03 GMT) Full text and rfc822 format available.

This bug report was last modified 10 years and 245 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.