Plaster

diff
Copy the arguments to spawn() so they don't point into the Lisp heap. --- src/runtime/linux-os.c | 12 +++++++++++ src/runtime/run-program.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/runtime/linux-os.c b/src/runtime/linux-os.c index 95e8cfa180a3..3080a5ef4119 100644 --- a/src/runtime/linux-os.c +++ b/src/runtime/linux-os.c @@ -349,6 +349,18 @@ os_validate(os_vm_address_t addr, os_vm_size_t len) return 0; } +#if defined(LISP_FEATURE_SB_THREAD) && defined(MADV_DONTFORK) + /* When multi-threaded it's usafe to execute Lisp code after a + * fork(), so make sure Lisp pages are not copied into the new + * proces. The only caveat is that one can no longer use pinned + * Lisp arrays in the C code between fork() and exec(). Necessary + * data has to be stack-allocated or copied into the C heap before + * fork(). */ + if ((uintptr_t)addr >= READ_ONLY_SPACE_START) { + (void) madvise(addr, len, MADV_DONTFORK); + } +#endif + #ifdef LISP_FEATURE_ALPHA len=(len+(os_vm_page_size-1))&(~(os_vm_page_size-1)); diff --git a/src/runtime/run-program.c b/src/runtime/run-program.c index 4521146e36f5..632696a07113 100644 --- a/src/runtime/run-program.c +++ b/src/runtime/run-program.c @@ -18,6 +18,7 @@ #ifndef LISP_FEATURE_WIN32 #include <stdlib.h> +#include <string.h> #include <sys/file.h> #include <sys/types.h> #include <signal.h> @@ -28,6 +29,7 @@ #include <sys/wait.h> #include <sys/ioctl.h> #include <termios.h> +#include <sys/mman.h> #include <errno.h> #ifdef LISP_FEATURE_OPENBSD @@ -99,7 +101,7 @@ set_pty(char *pty_name) #endif /* !LISP_FEATURE_OPENBSD */ extern char **environ; -int spawn(char *program, char *argv[], int sin, int sout, int serr, +int do_spawn(char *program, char *argv[], int sin, int sout, int serr, int search, char *envp[], char *pty_name, int wait, char *pwd) { pid_t pid; @@ -234,6 +236,55 @@ int spawn(char *program, char *argv[], int sin, int sout, int serr, } _exit(failure_code); } + +char** copy_strlist(char **sv) { + unsigned i, len = 0; + if(sv == NULL) { return NULL; } + while(sv[len++] != NULL) {}; + char **copy_sv = calloc(sizeof(char*), len); + for(i = 0; i < len - 1; i++) { + copy_sv[i] = strdup(sv[i]); + } + copy_sv[len-1] = NULL; + return copy_sv; +} + +void free_strlist(char **sv) { + unsigned i = 0; + if(sv == NULL) { return; } + while(sv[i] != NULL) { free(sv[i++]); } + free(sv); +} + +int spawn(char *program, char *argv[], int sin, int sout, int serr, + int search, char *envp[], char *pty_name, int wait, char *pwd) +{ + +#if defined(LISP_FEATURE_SB_THREAD) && defined(MADV_DONTFORK) + /* Copy the arguments because they most likely point into the Lisp + * heap, and those pages won't be available because of + * MADV_DONTFORK. */ + char *program__ = strdup(program); + char **argv__ = copy_strlist(argv); + char **envp__ = copy_strlist(envp); + char *pty_name__ = pty_name ? strdup(pty_name) : NULL; + char *pwd__ = pwd ? strdup(pwd) : NULL; + + int ret = do_spawn(program__, argv__, sin, sout, serr, + search, envp__, pty_name__, wait, pwd__); + + free(program__); + free_strlist(argv__); + free_strlist(envp__); + if(pty_name) { free(pty_name__); } + if(pwd) { free(pwd__); } + + return ret; +#else + return do_spawn(program, argv, sin, sout, serr, + search, envp, pty_name, wait, pwd); +#endif +} #else /* !LISP_FEATURE_WIN32 */ # include <windows.h>