]> code.delx.au - gnu-emacs/blobdiff - src/callproc.c
Fix the MS-Windows build broken by SAFE_ALLOCA changes.
[gnu-emacs] / src / callproc.c
index 9fbc7e5b713a0e01cda8561b8dbce8aedde575f7..271743021b68b7f5661d290969d6cd34c8e9594f 100644 (file)
@@ -129,7 +129,7 @@ encode_current_directory (void)
 
   if (STRING_MULTIBYTE (dir))
     dir = ENCODE_FILE (dir);
-  if (! file_accessible_directory_p (SSDATA (dir)))
+  if (! file_accessible_directory_p (dir))
     report_file_error ("Setting current directory",
                       BVAR (current_buffer, directory));
 
@@ -466,7 +466,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
       && SREF (path, 1) == ':')
     path = Fsubstring (path, make_number (2), Qnil);
 
-  new_argv = SAFE_ALLOCA ((nargs > 4 ? nargs - 2 : 2) * sizeof *new_argv);
+  SAFE_NALLOCA (new_argv, 1, nargs < 4 ? 2 : nargs - 2);
 
   {
     struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
@@ -982,7 +982,7 @@ create_temp_file (ptrdiff_t nargs, Lisp_Object *args,
 
     count = SPECPDL_INDEX ();
     record_unwind_protect_nothing ();
-    fd = mkostemp (tempfile, O_CLOEXEC);
+    fd = mkostemp (tempfile, O_BINARY | O_CLOEXEC);
     if (fd < 0)
       report_file_error ("Failed to open temporary file using pattern",
                         pattern);
@@ -1151,6 +1151,25 @@ add_env (char **env, char **new_env, char *string)
   return new_env;
 }
 
+#ifndef DOS_NT
+
+/* 'exec' failed inside a child running NAME, with error number ERR.
+   Report the error and exit the child.  */
+
+static _Noreturn void
+exec_failed (char const *name, int err)
+{
+  /* Avoid deadlock if the child's perror writes to a full pipe; the
+     pipe's reader is the parent, but with vfork the parent can't
+     run until the child exits.  Truncate the diagnostic instead.  */
+  fcntl (STDERR_FILENO, F_SETFL, O_NONBLOCK);
+
+  errno = err;
+  emacs_perror (name);
+  _exit (err == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
+}
+#endif
+
 /* This is the last thing run in a newly forked inferior
    either synchronous or asynchronous.
    Copy descriptors IN, OUT and ERR as descriptors 0, 1 and 2.
@@ -1174,8 +1193,6 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
   int cpid;
   HANDLE handles[3];
 #else
-  int exec_errno;
-
   pid_t pid = getpid ();
 #endif /* WINDOWSNT */
 
@@ -1196,6 +1213,13 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
        on that.  */
     pwd_var = xmalloc (i + 5);
 #else
+    /* WINDOWSNT doesn't define exec_failed, and doesn't need this
+       test, since a directory name cannot be longer than 260
+       characters, i.e. 260 * 4 = 1040 UTF-8 bytes.  */
+#ifndef WINDOWSNT
+    if (MAX_ALLOCA - 5 < i)
+      exec_failed (new_argv[0], ENOMEM);
+#endif
     pwd_var = alloca (i + 5);
 #endif
     temp = pwd_var + 4;
@@ -1262,6 +1286,10 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
       }
 
     /* new_length + 2 to include PWD and terminating 0.  */
+#ifndef WINDOWSNT
+    if (MAX_ALLOCA / sizeof *env - 2 < new_length)
+      exec_failed (new_argv[0], ENOMEM);
+#endif
     env = new_env = alloca ((new_length + 2) * sizeof *env);
     /* If we have a PWD envvar, pass one down,
        but with corrected value.  */
@@ -1270,7 +1298,14 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
 
     if (STRINGP (display))
       {
-       char *vdata = alloca (sizeof "DISPLAY=" + SBYTES (display));
+       char *vdata;
+
+       /* WINDOWSNT doesn't have $DISPLAY.  */
+#ifndef WINDOWSNT
+       if (MAX_ALLOCA - sizeof "DISPLAY=" < SBYTES (display))
+         exec_failed (new_argv[0], ENOMEM);
+#endif
+       vdata = alloca (sizeof "DISPLAY=" + SBYTES (display));
        strcpy (vdata, "DISPLAY=");
        strcat (vdata, SSDATA (display));
        new_env = add_env (env, new_env, vdata);
@@ -1345,16 +1380,7 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
   tcsetpgrp (0, pid);
 
   execve (new_argv[0], new_argv, env);
-  exec_errno = errno;
-
-  /* Avoid deadlock if the child's perror writes to a full pipe; the
-     pipe's reader is the parent, but with vfork the parent can't
-     run until the child exits.  Truncate the diagnostic instead.  */
-  fcntl (STDERR_FILENO, F_SETFL, O_NONBLOCK);
-
-  errno = exec_errno;
-  emacs_perror (new_argv[0]);
-  _exit (exec_errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
+  exec_failed (new_argv[0], errno);
 
 #else /* MSDOS */
   pid = run_msdos_command (new_argv, pwd_var + 4, in, out, err, env);
@@ -1488,14 +1514,14 @@ If optional parameter ENV is a list, then search this list instead of
 }
 
 /* A version of getenv that consults the Lisp environment lists,
-   easily callable from C.  */
+   easily callable from C.  This is usually called from egetenv.  */
 char *
-egetenv (const char *var)
+egetenv_internal (const char *var, ptrdiff_t len)
 {
   char *value;
   ptrdiff_t valuelen;
 
-  if (getenv_internal (var, strlen (var), &value, &valuelen, Qnil))
+  if (getenv_internal (var, len, &value, &valuelen, Qnil))
     return value;
   else
     return 0;
@@ -1543,20 +1569,13 @@ init_callproc_1 (void)
 void
 init_callproc (void)
 {
-  char *data_dir = egetenv ("EMACSDATA");
+  bool data_dir = egetenv ("EMACSDATA") != 0;
 
-  register char * sh;
+  char *sh;
   Lisp_Object tempdir;
 #ifdef HAVE_NS
   if (data_dir == 0)
-    {
-      const char *etc_dir = ns_etc_directory ();
-      if (etc_dir)
-        {
-          data_dir = alloca (strlen (etc_dir) + 1);
-          strcpy (data_dir, etc_dir);
-        }
-    }
+    data_dir == ns_etc_directory () != 0;
 #endif
 
   if (!NILP (Vinstallation_directory))
@@ -1625,12 +1644,12 @@ init_callproc (void)
 #endif
     {
       tempdir = Fdirectory_file_name (Vexec_directory);
-      if (! file_accessible_directory_p (SSDATA (tempdir)))
+      if (! file_accessible_directory_p (tempdir))
        dir_warning ("arch-dependent data dir", Vexec_directory);
     }
 
   tempdir = Fdirectory_file_name (Vdata_directory);
-  if (! file_accessible_directory_p (SSDATA (tempdir)))
+  if (! file_accessible_directory_p (tempdir))
     dir_warning ("arch-independent data dir", Vdata_directory);
 
   sh = getenv ("SHELL");