X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/da41ffdd089b529c3d5216412d95840e065c3fe3..785adfcc8dee02ac544f80e4f7f8d3d5b2965981:/src/callproc.c diff --git a/src/callproc.c b/src/callproc.c index 2f68ea6f32..0fdf278073 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -1,6 +1,6 @@ /* Synchronous subprocess invocation for GNU Emacs. -Copyright (C) 1985-1988, 1993-1995, 1999-2014 Free Software Foundation, +Copyright (C) 1985-1988, 1993-1995, 1999-2015 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -127,9 +127,17 @@ encode_current_directory (void) dir = expand_and_dir_to_file (dir, Qnil); + if (NILP (Ffile_accessible_directory_p (dir))) + report_file_error ("Setting current directory", + BVAR (current_buffer, directory)); + + /* Remove "/:" from dir. */ + if (! NILP (Fstring_match (build_string ("^/:"), dir, Qnil))) + dir = Fsubstring (dir, make_number (2), Qnil); + 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 +474,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; @@ -632,6 +640,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, int volatile fd_error_volatile = fd_error; int volatile filefd_volatile = filefd; ptrdiff_t volatile count_volatile = count; + ptrdiff_t volatile sa_avail_volatile = sa_avail; ptrdiff_t volatile sa_count_volatile = sa_count; char **volatile new_argv_volatile = new_argv; int volatile callproc_fd_volatile[CALLPROC_FDS]; @@ -648,6 +657,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, fd_error = fd_error_volatile; filefd = filefd_volatile; count = count_volatile; + sa_avail = sa_avail_volatile; sa_count = sa_count_volatile; new_argv = new_argv_volatile; @@ -842,7 +852,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, (process_coding.dst_pos_byte + process_coding.produced), 0); - display_on_the_fly = 0; + display_on_the_fly = false; process_coding = saved_coding; carryover = nread; /* Make the above condition always fail in the future. */ @@ -874,9 +884,9 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, /* This variable might have been set to 0 for code detection. In that case, set it back to 1 because we should have already detected a coding system. */ - display_on_the_fly = 1; + display_on_the_fly = true; } - immediate_quit = 1; + immediate_quit = true; QUIT; } give_up: ; @@ -1151,6 +1161,39 @@ 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. + Possibly a vforked child needed to allocate a large vector on the + stack; such a child cannot fall back on malloc because that might + mess up the allocator's data structures in the parent. + 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); +} + +#else + +/* Do nothing. There is no need to fail, as DOS_NT platforms do not + fork and exec, and handle alloca exhaustion in a different way. */ + +static void +exec_failed (char const *name, int err) +{ +} + +#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 +1217,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,11 +1237,13 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, on that. */ pwd_var = xmalloc (i + 5); #else + if (MAX_ALLOCA - 5 < i) + exec_failed (new_argv[0], ENOMEM); pwd_var = alloca (i + 5); #endif temp = pwd_var + 4; memcpy (pwd_var, "PWD=", 4); - strcpy (temp, SSDATA (current_dir)); + lispstpcpy (temp, current_dir); #ifndef DOS_NT /* We can't signal an Elisp error here; we're in a vfork. Since @@ -1262,6 +1305,8 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, } /* new_length + 2 to include PWD and terminating 0. */ + if (MAX_ALLOCA / sizeof *env - 2 < new_length) + exec_failed (new_argv[0], ENOMEM); env = new_env = alloca ((new_length + 2) * sizeof *env); /* If we have a PWD envvar, pass one down, but with corrected value. */ @@ -1270,9 +1315,10 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, if (STRINGP (display)) { + if (MAX_ALLOCA - sizeof "DISPLAY=" < SBYTES (display)) + exec_failed (new_argv[0], ENOMEM); char *vdata = alloca (sizeof "DISPLAY=" + SBYTES (display)); - strcpy (vdata, "DISPLAY="); - strcat (vdata, SSDATA (display)); + lispstpcpy (stpcpy (vdata, "DISPLAY="), display); new_env = add_env (env, new_env, vdata); } @@ -1345,16 +1391,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 +1525,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 +1580,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 +1655,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");