Subject: 'volatile' needed for local variables around vfork

From: Paul Eggert <[email-masked]>
Date: Sat, 19 Mar 2011 21:39:30 -0700

In three places, GNU Emacs assumes that a local variable
is preserved after a successful vfork, but on some architectures
these variables may be clobbered.  (I found this problem by
compiling with gcc -Wclobbered.)  I plan to address this problem
with the following patch:

2011-03-19  Paul Eggert  <[email-masked]>
 
	* callproc.c (Fcall_process): Use 'volatile' to avoid vfork clobbering.
	* process.c (create_process): Likewise.
	* sysdep.c (sys_subshell): Likewise.
	Previously, the sys_subshell 'volatile' was incorrectly IF_LINTted out.

=== modified file 'src/callproc.c'
--- src/callproc.c	2011-03-18 04:45:18 +0000
+++ src/callproc.c	2011-03-18 05:56:46 +0000
@@ -180,7 +180,7 @@
   (int nargs, register Lisp_Object *args)
 {
   Lisp_Object infile, buffer, current_dir, path;
-  int display_p;
+  volatile int display_p_volatile;
   int fd[2];
   int filefd;
   register int pid;
@@ -190,6 +190,7 @@
   int bufsize = CALLPROC_BUFFER_SIZE_MIN;
   int count = SPECPDL_INDEX ();
 
+  const unsigned char **volatile new_argv_volatile;
   register const unsigned char **new_argv;
   /* File to use for stderr in the child.
      t means use same as standard output.  */
@@ -343,7 +344,7 @@
     UNGCPRO;
   }
 
-  display_p = INTERACTIVE && nargs >= 4 && !NILP (args[3]);
+  display_p_volatile = INTERACTIVE && nargs >= 4 && !NILP (args[3]);
 
   filefd = emacs_open (SSDATA (infile), O_RDONLY, 0);
   if (filefd < 0)
@@ -371,7 +372,7 @@
       && SREF (path, 1) == ':')
     path = Fsubstring (path, make_number (2), Qnil);
 
-  new_argv = (const unsigned char **)
+  new_argv_volatile = new_argv = (const unsigned char **)
     alloca (max (2, nargs - 2) * sizeof (char *));
   if (nargs > 4)
     {
@@ -542,6 +543,8 @@
 
     pid = vfork ();
 
+    new_argv = new_argv_volatile;
+
     if (pid == 0)
       {
 	if (fd[0] >= 0)
@@ -673,6 +676,7 @@
     int first = 1;
     EMACS_INT total_read = 0;
     int carryover = 0;
+    int display_p = display_p_volatile;
     int display_on_the_fly = display_p;
     struct coding_system saved_coding;

=== modified file 'src/process.c'
--- src/process.c	2011-03-20 02:48:50 +0000
+++ src/process.c	2011-03-20 03:07:54 +0000
@@ -1912,8 +1912,7 @@
     /* child_setup must clobber environ on systems with true vfork.
        Protect it from permanent change.  */
     char **save_environ = environ;
-
-    current_dir = ENCODE_FILE (current_dir);
+    volatile Lisp_Object encoded_current_dir = ENCODE_FILE (current_dir);
 
 #ifndef WINDOWSNT
     pid = vfork ();
@@ -2054,13 +2053,13 @@
 	  child_setup_tty (xforkout);
 #ifdef WINDOWSNT
 	pid = child_setup (xforkin, xforkout, xforkout,
-			   new_argv, 1, current_dir);
+			   new_argv, 1, encoded_current_dir);
 #else  /* not WINDOWSNT */
 #ifdef FD_CLOEXEC
 	emacs_close (wait_child_setup[0]);
 #endif
 	child_setup (xforkin, xforkout, xforkout,
-		     new_argv, 1, current_dir);
+		     new_argv, 1, encoded_current_dir);
 #endif /* not WINDOWSNT */
       }
     environ = save_environ;

=== modified file 'src/sysdep.c'
--- src/sysdep.c	2011-03-14 23:31:21 +0000
+++ src/sysdep.c	2011-03-18 05:50:40 +0000
@@ -488,7 +488,8 @@
   int pid;
   struct save_signal saved_handlers[5];
   Lisp_Object dir;
-  unsigned char * IF_LINT (volatile) str = 0;
+  unsigned char *volatile str_volatile = 0;
+  unsigned char *str;
   int len;
 
   saved_handlers[0].code = SIGINT;
@@ -512,7 +513,7 @@
     goto xyzzy;
 
   dir = expand_and_dir_to_file (Funhandled_file_name_directory (dir), Qnil);
-  str = (unsigned char *) alloca (SCHARS (dir) + 2);
+  str_volatile = str = (unsigned char *) alloca (SCHARS (dir) + 2);
   len = SCHARS (dir);
   memcpy (str, SDATA (dir), len);
   if (str[len - 1] != '/') str[len++] = '/';
@@ -544,6 +545,7 @@
 	sh = "sh";
 
       /* Use our buffer's default directory for the subshell.  */
+      str = str_volatile;
       if (str && chdir ((char *) str) != 0)
 	{
 #ifndef DOS_NT