* [PATCH v2 0/4] setenv/putenv errors @ 2011-12-14 14:07 Erik Faye-Lund 2011-12-14 14:07 ` [PATCH v2 1/4] compat/setenv.c: update errno when erroring out Erik Faye-Lund ` (3 more replies) 0 siblings, 4 replies; 9+ messages in thread From: Erik Faye-Lund @ 2011-12-14 14:07 UTC (permalink / raw) To: git; +Cc: peff, gitster, schwab Here's v2 of this series. It grew a bit since the last round, as I figured fixing the error-paths in compat/setenv.c made sense to do while I was at it, considering how Windows (which is one of the few likely platforms to be able to actually trigger this issue) use it. Erik Faye-Lund (4): compat/setenv.c: update errno when erroring out compat/setenv.c: error if name contains '=' wrapper: supply xsetenv and xputenv use wrapper for unchecked setenv/putenv calls builtin/clone.c | 2 +- builtin/commit.c | 6 +++--- builtin/help.c | 4 ++-- builtin/init-db.c | 2 +- builtin/merge.c | 4 ++-- builtin/notes.c | 2 +- builtin/remote-ext.c | 4 ++-- builtin/revert.c | 2 +- compat/setenv.c | 10 ++++++++-- config.c | 2 +- exec_cmd.c | 4 ++-- git-compat-util.h | 2 ++ git.c | 18 +++++++++--------- pager.c | 2 +- run-command.c | 2 +- setup.c | 6 +++--- wrapper.c | 14 ++++++++++++++ 17 files changed, 54 insertions(+), 32 deletions(-) -- 1.7.7.1.msysgit.0.272.g9e47e ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/4] compat/setenv.c: update errno when erroring out 2011-12-14 14:07 [PATCH v2 0/4] setenv/putenv errors Erik Faye-Lund @ 2011-12-14 14:07 ` Erik Faye-Lund 2011-12-14 14:07 ` [PATCH v2 2/4] compat/setenv.c: error if name contains '=' Erik Faye-Lund ` (2 subsequent siblings) 3 siblings, 0 replies; 9+ messages in thread From: Erik Faye-Lund @ 2011-12-14 14:07 UTC (permalink / raw) To: git; +Cc: peff, gitster, schwab Previously, gitsetenv didn't update errno as it should when erroring out. Fix this. Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com> --- compat/setenv.c | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compat/setenv.c b/compat/setenv.c index 3a22ea7..89947b7 100644 --- a/compat/setenv.c +++ b/compat/setenv.c @@ -6,7 +6,10 @@ int gitsetenv(const char *name, const char *value, int replace) size_t namelen, valuelen; char *envstr; - if (!name || !value) return -1; + if (!name || !value) { + errno = EINVAL; + return -1; + } if (!replace) { char *oldval = NULL; oldval = getenv(name); @@ -16,7 +19,10 @@ int gitsetenv(const char *name, const char *value, int replace) namelen = strlen(name); valuelen = strlen(value); envstr = malloc((namelen + valuelen + 2)); - if (!envstr) return -1; + if (!envstr) { + errno = ENOMEM; + return -1; + } memcpy(envstr, name, namelen); envstr[namelen] = '='; -- 1.7.7.1.msysgit.0.272.g9e47e ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 2/4] compat/setenv.c: error if name contains '=' 2011-12-14 14:07 [PATCH v2 0/4] setenv/putenv errors Erik Faye-Lund 2011-12-14 14:07 ` [PATCH v2 1/4] compat/setenv.c: update errno when erroring out Erik Faye-Lund @ 2011-12-14 14:07 ` Erik Faye-Lund 2011-12-14 14:07 ` [PATCH v2 3/4] wrapper: supply xsetenv and xputenv Erik Faye-Lund 2011-12-14 14:07 ` [PATCH v2 4/4] use wrapper for unchecked setenv/putenv calls Erik Faye-Lund 3 siblings, 0 replies; 9+ messages in thread From: Erik Faye-Lund @ 2011-12-14 14:07 UTC (permalink / raw) To: git; +Cc: peff, gitster, schwab According to POSIX, setenv should error out with EINVAL if it's asked to set an environment variable whose name contains an equals sign. Implement this detail in our compatibility-fallback. Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com> --- compat/setenv.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/compat/setenv.c b/compat/setenv.c index 89947b7..fc1439a 100644 --- a/compat/setenv.c +++ b/compat/setenv.c @@ -6,7 +6,7 @@ int gitsetenv(const char *name, const char *value, int replace) size_t namelen, valuelen; char *envstr; - if (!name || !value) { + if (!name || strchr(name, '=') || !value) { errno = EINVAL; return -1; } -- 1.7.7.1.msysgit.0.272.g9e47e ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 3/4] wrapper: supply xsetenv and xputenv 2011-12-14 14:07 [PATCH v2 0/4] setenv/putenv errors Erik Faye-Lund 2011-12-14 14:07 ` [PATCH v2 1/4] compat/setenv.c: update errno when erroring out Erik Faye-Lund 2011-12-14 14:07 ` [PATCH v2 2/4] compat/setenv.c: error if name contains '=' Erik Faye-Lund @ 2011-12-14 14:07 ` Erik Faye-Lund 2011-12-15 17:38 ` Junio C Hamano 2011-12-14 14:07 ` [PATCH v2 4/4] use wrapper for unchecked setenv/putenv calls Erik Faye-Lund 3 siblings, 1 reply; 9+ messages in thread From: Erik Faye-Lund @ 2011-12-14 14:07 UTC (permalink / raw) To: git; +Cc: peff, gitster, schwab Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com> --- git-compat-util.h | 2 ++ wrapper.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 0 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index 77062ed..ab17d53 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -439,6 +439,8 @@ extern int xdup(int fd); extern FILE *xfdopen(int fd, const char *mode); extern int xmkstemp(char *template); extern int xmkstemp_mode(char *template, int mode); +extern int xsetenv(const char *name, const char *val, int override); +extern int xputenv(const char *string); extern int odb_mkstemp(char *template, size_t limit, const char *pattern); extern int odb_pack_keep(char *name, size_t namesz, unsigned char *sha1); diff --git a/wrapper.c b/wrapper.c index 85f09df..8d172ac 100644 --- a/wrapper.c +++ b/wrapper.c @@ -381,3 +381,17 @@ int remove_or_warn(unsigned int mode, const char *file) { return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file); } + +int xsetenv(const char *name, const char *val, int overwrite) +{ + if (setenv(name, val, overwrite)) + die_errno("setenv failed to set '%s' to '%s'", name, val); + return 0; +} + +int xputenv(const char *string) +{ + if (putenv(string)) + die_errno("putenv failed to set '%s' ", string); + return 0; +} -- 1.7.7.1.msysgit.0.272.g9e47e ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 3/4] wrapper: supply xsetenv and xputenv 2011-12-14 14:07 ` [PATCH v2 3/4] wrapper: supply xsetenv and xputenv Erik Faye-Lund @ 2011-12-15 17:38 ` Junio C Hamano 2011-12-15 18:25 ` Erik Faye-Lund 0 siblings, 1 reply; 9+ messages in thread From: Junio C Hamano @ 2011-12-15 17:38 UTC (permalink / raw) To: Erik Faye-Lund; +Cc: git, peff, schwab Erik Faye-Lund <kusmabite@gmail.com> writes: > +extern int xsetenv(const char *name, const char *val, int override); > +extern int xputenv(const char *string); Actually, putenv(3) takes "char *string". I adjusted 3 & 4 locally before queuing, so there is no need for resend, and judging from the later part of the discussion, it seems that it may be better to use only the first two patches from this series after all. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 3/4] wrapper: supply xsetenv and xputenv 2011-12-15 17:38 ` Junio C Hamano @ 2011-12-15 18:25 ` Erik Faye-Lund 0 siblings, 0 replies; 9+ messages in thread From: Erik Faye-Lund @ 2011-12-15 18:25 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, peff, schwab On Thu, Dec 15, 2011 at 6:38 PM, Junio C Hamano <gitster@pobox.com> wrote: > Erik Faye-Lund <kusmabite@gmail.com> writes: > >> +extern int xsetenv(const char *name, const char *val, int override); >> +extern int xputenv(const char *string); > > Actually, putenv(3) takes "char *string". Ah, thanks for spotting. > I adjusted 3 & 4 locally before queuing, so there is no need for resend, > and judging from the later part of the discussion, it seems that it may be > better to use only the first two patches from this series after all. Yeah, I agree; patch 1 and 2 are the only ones that makes sense. ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 4/4] use wrapper for unchecked setenv/putenv calls 2011-12-14 14:07 [PATCH v2 0/4] setenv/putenv errors Erik Faye-Lund ` (2 preceding siblings ...) 2011-12-14 14:07 ` [PATCH v2 3/4] wrapper: supply xsetenv and xputenv Erik Faye-Lund @ 2011-12-14 14:07 ` Erik Faye-Lund 2011-12-14 18:16 ` Jeff King 3 siblings, 1 reply; 9+ messages in thread From: Erik Faye-Lund @ 2011-12-14 14:07 UTC (permalink / raw) To: git; +Cc: peff, gitster, schwab This avoids us from accidentally dropping state, possibly leading to unexpected behaviour. This is especially important on Windows, where the maximum size of the environment is 32 kB. Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com> --- builtin/clone.c | 2 +- builtin/commit.c | 6 +++--- builtin/help.c | 4 ++-- builtin/init-db.c | 2 +- builtin/merge.c | 4 ++-- builtin/notes.c | 2 +- builtin/remote-ext.c | 4 ++-- builtin/revert.c | 2 +- config.c | 2 +- exec_cmd.c | 4 ++-- git.c | 18 +++++++++--------- pager.c | 2 +- run-command.c | 2 +- setup.c | 6 +++--- 14 files changed, 30 insertions(+), 30 deletions(-) diff --git a/builtin/clone.c b/builtin/clone.c index efe8b6c..8d81c29 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -566,7 +566,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) atexit(remove_junk); sigchain_push_common(remove_junk_on_signal); - setenv(CONFIG_ENVIRONMENT, mkpath("%s/config", git_dir), 1); + xsetenv(CONFIG_ENVIRONMENT, mkpath("%s/config", git_dir), 1); if (safe_create_leading_directories_const(git_dir) < 0) die(_("could not create leading directories of '%s'"), git_dir); diff --git a/builtin/commit.c b/builtin/commit.c index e36e9ad..2b87da9 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -361,13 +361,13 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, die(_("unable to create temporary index")); old_index_env = getenv(INDEX_ENVIRONMENT); - setenv(INDEX_ENVIRONMENT, index_lock.filename, 1); + xsetenv(INDEX_ENVIRONMENT, index_lock.filename, 1); if (interactive_add(argc, argv, prefix, patch_interactive) != 0) die(_("interactive add failed")); if (old_index_env && *old_index_env) - setenv(INDEX_ENVIRONMENT, old_index_env, 1); + xsetenv(INDEX_ENVIRONMENT, old_index_env, 1); else unsetenv(INDEX_ENVIRONMENT); @@ -1023,7 +1023,7 @@ static int parse_and_validate_options(int argc, const char *argv[], if (edit_flag) use_editor = 1; if (!use_editor) - setenv("GIT_EDITOR", ":", 1); + xsetenv("GIT_EDITOR", ":", 1); /* Sanity check options */ if (amend && !current_head) diff --git a/builtin/help.c b/builtin/help.c index 61ff798..e7dc15b 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -330,7 +330,7 @@ static void setup_man_path(void) if (old_path) strbuf_addstr(&new_path, old_path); - setenv("MANPATH", new_path.buf, 1); + xsetenv("MANPATH", new_path.buf, 1); strbuf_release(&new_path); } @@ -371,7 +371,7 @@ static void show_man_page(const char *git_cmd) static void show_info_page(const char *git_cmd) { const char *page = cmd_to_page(git_cmd); - setenv("INFOPATH", system_path(GIT_INFO_PATH), 1); + xsetenv("INFOPATH", system_path(GIT_INFO_PATH), 1); execlp("info", "info", "gitman", page, (char *)NULL); die("no info viewer handled the request"); } diff --git a/builtin/init-db.c b/builtin/init-db.c index d07554c..21ff09e 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -537,7 +537,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) if (is_bare_repository_cfg == 1) { static char git_dir[PATH_MAX+1]; - setenv(GIT_DIR_ENVIRONMENT, + xsetenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), argc > 0); } diff --git a/builtin/merge.c b/builtin/merge.c index a1c8534..a4ae473 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -1257,7 +1257,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) strbuf_addstr(&buf, "merge"); for (i = 0; i < argc; i++) strbuf_addf(&buf, " %s", argv[i]); - setenv("GIT_REFLOG_ACTION", buf.buf, 0); + xsetenv("GIT_REFLOG_ACTION", buf.buf, 0); strbuf_reset(&buf); for (i = 0; i < argc; i++) { @@ -1267,7 +1267,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) remotes = &commit_list_insert(commit, remotes)->next; strbuf_addf(&buf, "GITHEAD_%s", sha1_to_hex(commit->object.sha1)); - setenv(buf.buf, argv[i], 1); + xsetenv(buf.buf, argv[i], 1); strbuf_reset(&buf); if (merge_remote_util(commit) && merge_remote_util(commit)->obj && diff --git a/builtin/notes.c b/builtin/notes.c index 10b8bc7..7b53c69 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -1076,7 +1076,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix) struct strbuf sb = STRBUF_INIT; strbuf_addstr(&sb, override_notes_ref); expand_notes_ref(&sb); - setenv("GIT_NOTES_REF", sb.buf, 1); + xsetenv("GIT_NOTES_REF", sb.buf, 1); strbuf_release(&sb); } diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c index 692c834..0b2169a 100644 --- a/builtin/remote-ext.c +++ b/builtin/remote-ext.c @@ -38,8 +38,8 @@ static char *strip_escapes(const char *str, const char *service, psoff = 4; /* Pass the service to command. */ - setenv("GIT_EXT_SERVICE", service, 1); - setenv("GIT_EXT_SERVICE_NOPREFIX", service + psoff, 1); + xsetenv("GIT_EXT_SERVICE", service, 1); + xsetenv("GIT_EXT_SERVICE_NOPREFIX", service + psoff, 1); /* Scan the length of argument. */ while (str[rpos] && (escape || str[rpos] != ' ')) { diff --git a/builtin/revert.c b/builtin/revert.c index 1ea525c..955a99f 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -1007,7 +1007,7 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts) struct commit_list *cur; int res; - setenv(GIT_REFLOG_ACTION, action_name(opts), 0); + xsetenv(GIT_REFLOG_ACTION, action_name(opts), 0); if (opts->allow_ff) assert(!(opts->signoff || opts->no_commit || opts->record_origin || opts->edit)); diff --git a/config.c b/config.c index 5ea101f..f461a62 100644 --- a/config.c +++ b/config.c @@ -43,7 +43,7 @@ void git_config_push_parameter(const char *text) strbuf_addch(&env, ' '); } sq_quote_buf(&env, text); - setenv(CONFIG_DATA_ENVIRONMENT, env.buf, 1); + xsetenv(CONFIG_DATA_ENVIRONMENT, env.buf, 1); strbuf_release(&env); } diff --git a/exec_cmd.c b/exec_cmd.c index 171e841..a5a92dd 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -63,7 +63,7 @@ void git_set_argv_exec_path(const char *exec_path) /* * Propagate this setting to external programs. */ - setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1); + xsetenv(EXEC_PATH_ENVIRONMENT, exec_path, 1); } @@ -108,7 +108,7 @@ void setup_path(void) else strbuf_addstr(&new_path, _PATH_DEFPATH); - setenv("PATH", new_path.buf, 1); + xsetenv("PATH", new_path.buf, 1); strbuf_release(&new_path); } diff --git a/git.c b/git.c index 8e34903..cb80de2 100644 --- a/git.c +++ b/git.c @@ -54,7 +54,7 @@ int check_pager_config(const char *cmd) static void commit_pager_choice(void) { switch (use_pager) { case 0: - setenv("GIT_PAGER", "cat", 1); + xsetenv("GIT_PAGER", "cat", 1); break; case 1: setup_pager(); @@ -109,7 +109,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--no-replace-objects")) { read_replace_refs = 0; - setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1); + xsetenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--git-dir")) { @@ -117,13 +117,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) fprintf(stderr, "No directory given for --git-dir.\n" ); usage(git_usage_string); } - setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1); + xsetenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1); if (envchanged) *envchanged = 1; (*argv)++; (*argc)--; } else if (!prefixcmp(cmd, "--git-dir=")) { - setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1); + xsetenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--namespace")) { @@ -131,13 +131,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) fprintf(stderr, "No namespace given for --namespace.\n" ); usage(git_usage_string); } - setenv(GIT_NAMESPACE_ENVIRONMENT, (*argv)[1], 1); + xsetenv(GIT_NAMESPACE_ENVIRONMENT, (*argv)[1], 1); if (envchanged) *envchanged = 1; (*argv)++; (*argc)--; } else if (!prefixcmp(cmd, "--namespace=")) { - setenv(GIT_NAMESPACE_ENVIRONMENT, cmd + 12, 1); + xsetenv(GIT_NAMESPACE_ENVIRONMENT, cmd + 12, 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--work-tree")) { @@ -145,19 +145,19 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) fprintf(stderr, "No directory given for --work-tree.\n" ); usage(git_usage_string); } - setenv(GIT_WORK_TREE_ENVIRONMENT, (*argv)[1], 1); + xsetenv(GIT_WORK_TREE_ENVIRONMENT, (*argv)[1], 1); if (envchanged) *envchanged = 1; (*argv)++; (*argc)--; } else if (!prefixcmp(cmd, "--work-tree=")) { - setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1); + xsetenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--bare")) { static char git_dir[PATH_MAX+1]; is_bare_repository_cfg = 1; - setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0); + xsetenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "-c")) { diff --git a/pager.c b/pager.c index 975955b..d3a1299 100644 --- a/pager.c +++ b/pager.c @@ -76,7 +76,7 @@ void setup_pager(void) if (!pager) return; - setenv("GIT_PAGER_IN_USE", "true", 1); + xsetenv("GIT_PAGER_IN_USE", "true", 1); /* spawn the pager */ pager_argv[0] = pager; diff --git a/run-command.c b/run-command.c index 1c51043..37abbde 100644 --- a/run-command.c +++ b/run-command.c @@ -258,7 +258,7 @@ fail_pipe: if (cmd->env) { for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) - putenv((char *)*cmd->env); + xputenv((char *)*cmd->env); else unsetenv(*cmd->env); } diff --git a/setup.c b/setup.c index 61c22e6..06f38d0 100644 --- a/setup.c +++ b/setup.c @@ -309,7 +309,7 @@ void setup_work_tree(void) * if $GIT_WORK_TREE is set relative */ if (getenv(GIT_WORK_TREE_ENVIRONMENT)) - setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1); + xsetenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1); set_git_dir(relative_path(git_dir, work_tree)); initialized = 1; @@ -683,9 +683,9 @@ const char *setup_git_directory_gently(int *nongit_ok) prefix = setup_git_directory_gently_1(nongit_ok); if (prefix) - setenv("GIT_PREFIX", prefix, 1); + xsetenv("GIT_PREFIX", prefix, 1); else - setenv("GIT_PREFIX", "", 1); + xsetenv("GIT_PREFIX", "", 1); if (startup_info) { startup_info->have_repository = !nongit_ok || !*nongit_ok; -- 1.7.7.1.msysgit.0.272.g9e47e ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 4/4] use wrapper for unchecked setenv/putenv calls 2011-12-14 14:07 ` [PATCH v2 4/4] use wrapper for unchecked setenv/putenv calls Erik Faye-Lund @ 2011-12-14 18:16 ` Jeff King 2011-12-15 18:04 ` Erik Faye-Lund 0 siblings, 1 reply; 9+ messages in thread From: Jeff King @ 2011-12-14 18:16 UTC (permalink / raw) To: Erik Faye-Lund; +Cc: git, gitster, schwab On Wed, Dec 14, 2011 at 03:07:11PM +0100, Erik Faye-Lund wrote: > This avoids us from accidentally dropping state, possibly leading > to unexpected behaviour. I do think this is fine in a "be extra cautious" kind of way. > This is especially important on Windows, where the maximum size of > the environment is 32 kB. But does your patch actually detect that? As Andreas pointed out, these limits don't typically come into play at setenv time. Instead, the environment is allocated on the heap, and then the result is passed to exec/spawn, which will fail. So your patch is really detecting a failure to malloc, not an overflow of the environment size, and Windows is just as (un)likely to run out of heap as any other platform. You can check how your platform behaves by applying this patch: diff --git a/git.c b/git.c index f10e434..57f6b12 100644 --- a/git.c +++ b/git.c @@ -223,6 +223,16 @@ static int handle_alias(int *argcp, const char ***argv) alias_argv[i] = (*argv)[i]; alias_argv[argc] = NULL; + /* make gigantic environment */ + { + int len = 256 * 1024; + char *buf = xmalloc(len); + memset(buf, 'z', len); + buf[len-1] = '\0'; + if (setenv("FOO", buf, 1)) + die("setenv failed"); + } + ret = run_command_v_opt(alias_argv, RUN_USING_SHELL); if (ret >= 0) /* normal exit */ exit(ret); and then running: git -c alias.foo='!echo ok' foo which yields: fatal: cannot exec 'echo ok': Argument list too long on Linux. -Peff PS I tried to come up with an invocation of git that would demonstrate this, but it turns out it's really hard. The contents of environment variables we set are either constants, come from the environment (so they can't be too big already!), or come from filesystem paths. So it's possible to overflow now, but you have to have a nearly-full environment in the first place, and then have a long path that tips it over the limit. ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 4/4] use wrapper for unchecked setenv/putenv calls 2011-12-14 18:16 ` Jeff King @ 2011-12-15 18:04 ` Erik Faye-Lund 0 siblings, 0 replies; 9+ messages in thread From: Erik Faye-Lund @ 2011-12-15 18:04 UTC (permalink / raw) To: Jeff King; +Cc: git, gitster, schwab On Wed, Dec 14, 2011 at 7:16 PM, Jeff King <peff@peff.net> wrote: > On Wed, Dec 14, 2011 at 03:07:11PM +0100, Erik Faye-Lund wrote: > >> This avoids us from accidentally dropping state, possibly leading >> to unexpected behaviour. > > I do think this is fine in a "be extra cautious" kind of way. > >> This is especially important on Windows, where the maximum size of >> the environment is 32 kB. > > But does your patch actually detect that? As Andreas pointed out, these > limits don't typically come into play at setenv time. Instead, the > environment is allocated on the heap, and then the result is passed to > exec/spawn, which will fail. > > So your patch is really detecting a failure to malloc, not an overflow > of the environment size, and Windows is just as (un)likely to run out of > heap as any other platform. > You are right; I just assumed that our setenv was implemented on top of SetEnvironmentVariable, which does impose max-limits on setting (if I read the documentation correctly): http://msdn.microsoft.com/en-us/library/windows/desktop/ms686206(v=vs.85).aspx But we don't. We have mingw_setenv, which simply modifies environ. > You can check how your platform behaves by applying this patch: > > diff --git a/git.c b/git.c > index f10e434..57f6b12 100644 > --- a/git.c > +++ b/git.c > @@ -223,6 +223,16 @@ static int handle_alias(int *argcp, const char ***argv) > alias_argv[i] = (*argv)[i]; > alias_argv[argc] = NULL; > > + /* make gigantic environment */ > + { > + int len = 256 * 1024; > + char *buf = xmalloc(len); > + memset(buf, 'z', len); > + buf[len-1] = '\0'; > + if (setenv("FOO", buf, 1)) > + die("setenv failed"); > + } > + > ret = run_command_v_opt(alias_argv, RUN_USING_SHELL); > if (ret >= 0) /* normal exit */ > exit(ret); > > and then running: > > git -c alias.foo='!echo ok' foo > > which yields: > > fatal: cannot exec 'echo ok': Argument list too long > > on Linux. > Yeah, but I'm getting: $ git -c alias.foo='!echo ok' foo ok Which is strange to me. But if I do: $ git -c alias.foo='!echo $FOO' foo it does echo a bunch of 'z's. And we get the expected amount: $ git -c alias.foo='!echo $FOO' foo | wc -c 262144 This strikes me as very strange, because we end up calling the ANSI version of CreateProcess with an environment-block beyond 32767 chars, which MSDN says should fail: "The ANSI version of this function, CreateProcessA fails if the total size of the environment block for the process exceeds 32,767 characters." http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx Oh well, this is strange behavior in a good way; I'm not going to complain :P ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2011-12-15 18:26 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2011-12-14 14:07 [PATCH v2 0/4] setenv/putenv errors Erik Faye-Lund 2011-12-14 14:07 ` [PATCH v2 1/4] compat/setenv.c: update errno when erroring out Erik Faye-Lund 2011-12-14 14:07 ` [PATCH v2 2/4] compat/setenv.c: error if name contains '=' Erik Faye-Lund 2011-12-14 14:07 ` [PATCH v2 3/4] wrapper: supply xsetenv and xputenv Erik Faye-Lund 2011-12-15 17:38 ` Junio C Hamano 2011-12-15 18:25 ` Erik Faye-Lund 2011-12-14 14:07 ` [PATCH v2 4/4] use wrapper for unchecked setenv/putenv calls Erik Faye-Lund 2011-12-14 18:16 ` Jeff King 2011-12-15 18:04 ` Erik Faye-Lund
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).