diff --git a/ChangeLog b/ChangeLog index 95c19c875b..1da6db1df1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +Sun Jun 3 23:47:30 2012 Tanaka Akira + + * include/ruby/intern.h (rb_exec_arg): remove argc and argv fields. + add use_shell, argv_str and argv_buf fields. + + * process.c (rb_proc_exec_e): don't split shell command line arguments + here to avoid memory allocation in a child process. + (rb_exec_fillarg): split shell command line arguments here. + (proc_exec_v): takes argv_str argument instead of argv. + (rb_proc_exec_ne): removed. + (rb_proc_exec_n): removed. + (rb_run_exec_options_err): don't initialize the removed fields. + (rb_exec_err): don't initialize the removed fields. + call proc_exec_v directly instead of rb_proc_exec_ne. + (rb_spawn_process): use use_shell field. + Sun Jun 3 21:53:00 2012 NARUSE, Yui * GPL: update text of GPLv2. [ruby-core:44488] [Bug #6328] diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 693e52b5bd..e963d99b06 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -592,12 +592,13 @@ VALUE rb_sym_all_symbols(void); void rb_last_status_set(int status, rb_pid_t pid); VALUE rb_last_status_get(void); struct rb_exec_arg { - int argc; - VALUE *argv; const char *prog; VALUE options; VALUE redirect_fds; VALUE progname; + int use_shell; + VALUE argv_str; + VALUE argv_buf; VALUE envp_str; VALUE envp_buf; }; diff --git a/process.c b/process.c index 2bc5eac599..7851af164d 100644 --- a/process.c +++ b/process.c @@ -1068,19 +1068,22 @@ exec_with_sh(const char *prog, char **argv) #ifdef __native_client__ static int -proc_exec_v(char **argv, const char *prog, VALUE envp_str) +proc_exec_v(const char *prog, VALUE argv_str, VALUE envp_str) { rb_notimplement(); } #else static int -proc_exec_v(char **argv, const char *prog, VALUE envp_str) +proc_exec_v(const char *prog, VALUE argv_str, VALUE envp_str) { + char **argv; char fbuf[MAXPATHLEN]; # if defined(__EMX__) || defined(OS2) char **new_argv = NULL; # endif + argv = (char **)RSTRING_PTR(argv_str); + if (!prog) prog = argv[0]; prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf)); @@ -1133,32 +1136,6 @@ proc_exec_v(char **argv, const char *prog, VALUE envp_str) } #endif -static int -rb_proc_exec_ne(int argc, VALUE *argv, const char *prog, VALUE envp_str) -{ - char **args; - int i; - int ret = -1; - VALUE v; - - args = ALLOC_ARGV(argc+1, v); - for (i=0; i()~&|\\$;'`\"\n",*s)) { #if defined(__CYGWIN32__) || defined(__EMX__) - char fbuf[MAXPATHLEN]; - char *shell = dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf)); - int status = -1; - before_exec(); - if (shell) - execl(shell, "sh", "-c", str, (char *) NULL); - else - status = system(str); - after_exec(); - if (status != -1) - exit(status); + { + char fbuf[MAXPATHLEN]; + char *shell = dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf)); + int status = -1; + before_exec(); + if (shell) + execl(shell, "sh", "-c", str, (char *) NULL); + else + status = system(str); + after_exec(); + if (status != -1) + exit(status); + } #else - before_exec(); - if (envp_str) - execle("/bin/sh", "sh", "-c", str, (char *)NULL, (char **)RSTRING_PTR(envp_str)); - else - execl("/bin/sh", "sh", "-c", str, (char *)NULL); - preserving_errno(after_exec()); + before_exec(); + if (envp_str) + execle("/bin/sh", "sh", "-c", str, (char *)NULL, (char **)RSTRING_PTR(envp_str)); + else + execl("/bin/sh", "sh", "-c", str, (char *)NULL); + preserving_errno(after_exec()); #endif - return -1; - } - } - a = argv = ALLOC_ARGV_WITH_STR((s-str)/2+2, v, ss, s-str+1); - memcpy(ss, str, s-str); - ss[s-str] = '\0'; - if ((*a++ = strtok(ss, " \t")) != 0) { - while ((t = strtok(NULL, " \t")) != 0) { - *a++ = t; - } - *a = NULL; - } - if (argv[0]) { - ret = proc_exec_v(argv, NULL, envp_str); - } - else { - errno = ENOENT; - } - ALLOCV_END(v); - return ret; + return -1; #endif /* _WIN32 */ } #endif @@ -1857,10 +1804,73 @@ rb_exec_fillarg(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, str rb_ary_store(options, EXEC_OPTION_ENV, env); } - e->argc = argc; - e->argv = argv; + e->use_shell = argc == 0; e->prog = prog ? RSTRING_PTR(prog) : 0; e->progname = prog; + +#ifndef _WIN32 + if (e->use_shell) { + char *p; + int has_meta = 0; + int has_nonspace = 0; + for (p = RSTRING_PTR(prog); *p; p++) { + if (*p != ' ' && *p != '\t') + has_nonspace = 1; + if (strchr("*?{}[]<>()~&|\\$;'`\"\n", *p)) + has_meta = 1; + } + if (has_nonspace && !has_meta) { + /* avoid shell since no shell meta charactor found. */ + e->use_shell = 0; + } + if (!e->use_shell) { + VALUE argv_buf; + argv_buf = hide_obj(rb_str_buf_new(0)); + p = RSTRING_PTR(prog); + while (*p) { + while (*p == ' ' || *p == '\t') + p++; + if (*p) { + char *w = p; + while (*p && *p != ' ' && *p != '\t') + p++; + rb_str_buf_cat(argv_buf, w, p-w); + rb_str_buf_cat(argv_buf, "", 1); /* append '\0' */ + } + } + e->argv_buf = argv_buf; + e->progname = hide_obj(rb_str_new_cstr(RSTRING_PTR(argv_buf))); + e->prog = RSTRING_PTR(e->progname); + } + } +#endif + + if (!e->use_shell && !e->argv_buf) { + int i; + VALUE argv_buf; + argv_buf = rb_str_buf_new(0); + hide_obj(argv_buf); + for (i = 0; i < argc; i++) { + rb_str_buf_cat2(argv_buf, StringValueCStr(argv[i])); + rb_str_buf_cat(argv_buf, "", 1); /* append '\0' */ + } + e->argv_buf = argv_buf; + } + + if (e->argv_buf) { + char *p, *ep; + VALUE argv_str; + argv_str = hide_obj(rb_str_buf_new(sizeof(char*) * (argc + 1))); + p = RSTRING_PTR(e->argv_buf); + ep = p + RSTRING_LEN(e->argv_buf); + while (p < ep) { + rb_str_buf_cat(argv_str, (char *)&p, sizeof(p)); + p += strlen(p) + 1; + } + p = NULL; + rb_str_buf_cat(argv_str, (char *)&p, sizeof(p)); + e->argv_str = argv_str; + } } VALUE @@ -2433,8 +2443,6 @@ rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char return 0; if (s) { - s->argc = 0; - s->argv = NULL; s->prog = NULL; s->options = soptions = hide_obj(rb_ary_new()); s->redirect_fds = Qnil; @@ -2527,19 +2535,17 @@ rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s) int rb_exec_err(const struct rb_exec_arg *e, char *errmsg, size_t errmsg_buflen) { - int argc = e->argc; - VALUE *argv = e->argv; const char *prog = e->prog; if (rb_run_exec_options_err(e, NULL, errmsg, errmsg_buflen) < 0) { return -1; } - if (argc == 0) { + if (e->use_shell) { rb_proc_exec_e(prog, e->envp_str); } else { - rb_proc_exec_ne(argc, argv, prog, e->envp_str); + proc_exec_v(prog, e->argv_str, e->envp_str); } return -1; } @@ -3090,9 +3096,9 @@ rb_spawn_process(struct rb_exec_arg *earg, VALUE prog, char *errmsg, size_t errm argc = earg->argc; argv = earg->argv; - if (prog && argc) argv[0] = prog; + if (prog && !earg->use_shell) argv[0] = prog; # if defined HAVE_SPAWNV - if (!argc) { + if (earg->use_shell) { pid = proc_spawn(RSTRING_PTR(prog)); } else { @@ -3103,7 +3109,7 @@ rb_spawn_process(struct rb_exec_arg *earg, VALUE prog, char *errmsg, size_t errm rb_last_status_set(0x7f << 8, 0); # endif # else - if (argc) prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" ")); + if (!earg->use_shell) prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" ")); status = system(StringValuePtr(prog)); rb_last_status_set((status & 0xff) << 8, 0); # endif