From 8aac69038fa6c5f957559ca7e08a5e2e8f74d0fa Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 11 Jan 2019 17:15:00 -0500 Subject: get_super_prefix(): copy getenv() result The return value of getenv() is not guaranteed to remain valid across multiple calls (nor across calls to setenv()). Since this function caches the result for the length of the program, we must make a copy to ensure that it is still valid when we need it. Reported-by: Yngve N. Pettersen Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/environment.c b/environment.c index 3f3c8746..8fa10cc 100644 --- a/environment.c +++ b/environment.c @@ -107,7 +107,7 @@ char *git_work_tree_cfg; static char *git_namespace; -static const char *super_prefix; +static char *super_prefix; /* * Repository-local GIT_* environment variables; see cache.h for details. @@ -240,7 +240,7 @@ const char *get_super_prefix(void) { static int initialized; if (!initialized) { - super_prefix = getenv(GIT_SUPER_PREFIX_ENVIRONMENT); + super_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT)); initialized = 1; } return super_prefix; -- cgit v0.10.2-6-g49f6 From 406bab3811a220400da6a43da71346cbfc466fc9 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 11 Jan 2019 17:15:40 -0500 Subject: commit: copy saved getenv() result We save the result of $GIT_INDEX_FILE so that we can restore it after setting it to a new value and running add--interactive. However, the pointer returned by getenv() is not guaranteed to be valid after calling setenv(). This _usually_ works fine, but can fail if libc needs to reallocate the environment block during the setenv(). Let's just duplicate the string, so we know that it remains valid. In the long run it may be more robust to teach interactive_add() to take a set of environment variables to pass along to run-command when it execs add--interactive. And then we would not have to do this save/restore dance at all. But this is an easy fix in the meantime. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/builtin/commit.c b/builtin/commit.c index 83233ca..04f5b98 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -346,7 +346,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix if (write_locked_index(&the_index, &index_lock, 0)) die(_("unable to create temporary index")); - old_index_env = getenv(INDEX_ENVIRONMENT); + old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT)); setenv(INDEX_ENVIRONMENT, get_lock_file_path(&index_lock), 1); if (interactive_add(argc, argv, prefix, patch_interactive) != 0) @@ -356,6 +356,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix setenv(INDEX_ENVIRONMENT, old_index_env, 1); else unsetenv(INDEX_ENVIRONMENT); + FREE_AND_NULL(old_index_env); discard_cache(); read_cache_from(get_lock_file_path(&index_lock)); -- cgit v0.10.2-6-g49f6 From 423ff9bef003b41f81949e7a88d7278b48334ed4 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 11 Jan 2019 17:15:54 -0500 Subject: config: make a copy of $GIT_CONFIG string cmd_config() points our source filename pointer at the return value of getenv(), but that value may be invalidated by further calls to environment functions. Let's copy it to make sure it remains valid. We don't need to bother freeing it, as it remains part of the whole-process global state until we exit. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/builtin/config.c b/builtin/config.c index 97b58c4..752d0c6 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -595,7 +595,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) int nongit = !startup_info->have_repository; char *value; - given_config_source.file = getenv(CONFIG_ENVIRONMENT); + given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT)); argc = parse_options(argc, argv, prefix, builtin_config_options, builtin_config_usage, -- cgit v0.10.2-6-g49f6 From e5b07c539deefb13a4830fe9303e3d7590713f26 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 11 Jan 2019 17:16:31 -0500 Subject: init: make a copy of $GIT_DIR string We pass the result of getenv("GIT_DIR") to init_db() and assume that the string remains valid. But that's not guaranteed across calls to setenv() or even getenv(), although it often works in practice. Let's make a copy of the string so that we follow the rules. Note that we need to mark it with UNLEAK(), since the value persists until the end of program (but we have no opportunity to free it). This patch also handles $GIT_WORK_TREE the same way. It actually doesn't have as long a lifetime and is probably fine, but it's simpler to just treat the two side-by-side variables the same. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/builtin/init-db.c b/builtin/init-db.c index 12ddda7..dbb0d10 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -541,8 +541,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR * without --bare. Catch the error early. */ - git_dir = getenv(GIT_DIR_ENVIRONMENT); - work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT); + git_dir = xstrdup_or_null(getenv(GIT_DIR_ENVIRONMENT)); + work_tree = xstrdup_or_null(getenv(GIT_WORK_TREE_ENVIRONMENT)); if ((!git_dir || is_bare_repository_cfg == 1) && work_tree) die(_("%s (or --work-tree=) not allowed without " "specifying %s (or --git-dir=)"), @@ -581,6 +581,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) } UNLEAK(real_git_dir); + UNLEAK(git_dir); + UNLEAK(work_tree); flags |= INIT_DB_EXIST_OK; return init_db(git_dir, real_git_dir, template_dir, flags); -- cgit v0.10.2-6-g49f6 From d64bb065c0279e523db5270bbcf0ddda74fa9c8f Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 11 Jan 2019 17:16:55 -0500 Subject: merge-recursive: copy $GITHEAD strings If $GITHEAD_1234abcd is set in the environment, we use its value as a "better branch name" in generating conflict markers. However, we pick these better names early in the process, and the return value from getenv() is not guaranteed to stay valid. Let's make a copy of the returned string. And to make memory management easier, let's just always return an allocated string from better_branch_name(), so we know that it must always be freed. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c index 9b2f707..7545136 100644 --- a/builtin/merge-recursive.c +++ b/builtin/merge-recursive.c @@ -7,16 +7,16 @@ static const char builtin_merge_recursive_usage[] = "git %s ... -- ..."; -static const char *better_branch_name(const char *branch) +static char *better_branch_name(const char *branch) { static char githead_env[8 + GIT_MAX_HEXSZ + 1]; char *name; if (strlen(branch) != the_hash_algo->hexsz) - return branch; + return xstrdup(branch); xsnprintf(githead_env, sizeof(githead_env), "GITHEAD_%s", branch); name = getenv(githead_env); - return name ? name : branch; + return xstrdup(name ? name : branch); } int cmd_merge_recursive(int argc, const char **argv, const char *prefix) @@ -26,6 +26,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) int i, failed; struct object_id h1, h2; struct merge_options o; + char *better1, *better2; struct commit *result; init_merge_options(&o); @@ -70,13 +71,17 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) if (get_oid(o.branch2, &h2)) die(_("could not resolve ref '%s'"), o.branch2); - o.branch1 = better_branch_name(o.branch1); - o.branch2 = better_branch_name(o.branch2); + o.branch1 = better1 = better_branch_name(o.branch1); + o.branch2 = better2 = better_branch_name(o.branch2); if (o.verbosity >= 3) printf(_("Merging %s with %s\n"), o.branch1, o.branch2); failed = merge_recursive_generic(&o, &h1, &h2, bases_count, bases, &result); + + free(better1); + free(better2); + if (failed < 0) return 128; /* die() error code */ return failed; -- cgit v0.10.2-6-g49f6 From 0da0e9268b4825cafb27bb0e07b43fae30bb33da Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 11 Jan 2019 17:17:22 -0500 Subject: builtin_diff(): read $GIT_DIFF_OPTS closer to use The value returned by getenv() is not guaranteed to remain valid across other environment function calls. But in between our call and using the value, we run fill_textconv(), which may do quite a bit of work, including spawning sub-processes. We can make this safer by calling getenv() right before we actually look at its value. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano diff --git a/diff.c b/diff.c index db5e5e9..0920b12 100644 --- a/diff.c +++ b/diff.c @@ -3444,7 +3444,7 @@ static void builtin_diff(const char *name_a, o->found_changes = 1; } else { /* Crazy xdl interfaces.. */ - const char *diffopts = getenv("GIT_DIFF_OPTS"); + const char *diffopts; const char *v; xpparam_t xpp; xdemitconf_t xecfg; @@ -3487,12 +3487,15 @@ static void builtin_diff(const char *name_a, xecfg.flags |= XDL_EMIT_FUNCCONTEXT; if (pe) xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags); + + diffopts = getenv("GIT_DIFF_OPTS"); if (!diffopts) ; else if (skip_prefix(diffopts, "--unified=", &v)) xecfg.ctxlen = strtoul(v, NULL, 10); else if (skip_prefix(diffopts, "-u", &v)) xecfg.ctxlen = strtoul(v, NULL, 10); + if (o->word_diff) init_diff_words_data(&ecbdata, o, one, two); if (xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata, -- cgit v0.10.2-6-g49f6