Re: [PATCH v2 2/4] SANITIZE tests: fix memory leaks in t13*config*, add to whitelist
- From
Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- Date
- Jul 14, 2021, 22:56 UTC
- Message-ID
- <87h7gwzeps.fsf@evledraar.gmail.com>
- In-Reply-To
- <871ea493-e108-e748-0234-f929690ad2fd@ahunt.org>
On Wed, Jul 14 2021, Andrzej Hunt wrote:
Show 85 quoted lines
> On 14/07/2021 19:23, Ævar Arnfjörð Bjarmason wrote:
>> Fix a couple of trivial memory leaks introduced in 3efd0bedc6 (config:
>> add conditional include, 2017-03-01) and my own 867ad08a26 (hooks:
>> allow customizing where the hook directory is, 2016-05-04).
>> In the latter case the "fix" is UNLEAK() on the global
>> variable. This
>> allows us to run all t13*config* tests under SANITIZE=leak.
>> With this change we can now run almost the whole set of config.c
>> tests (t13*config) under SANITIZE=leak, so let's do so, with a few
>> exceptions:
>> * The test added in ce81b1da23 (config: add new way to pass config
>> via `--config-env`, 2021-01-12), it fails in GitHub CI, but passes
>> for me locally. Let's just skip it for now.
>> * Ditto the split_cmdline and "aliases of builtins" tests, the
>> former
>> required splitting up an existing test, there an issue with the test
>> that would have also been revealed by skipping it.
>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
>> ---
>> config.c | 17 ++++++++++++-----
>> t/t1300-config.sh | 16 ++++++++++------
>> t/test-lib.sh | 1 +
>> 3 files changed, 23 insertions(+), 11 deletions(-)
>> diff --git a/config.c b/config.c
>> index f9c400ad30..38e132c0e2 100644
>> --- a/config.c
>> +++ b/config.c
>> @@ -138,8 +138,10 @@ static int handle_path_include(const char *path, struct config_include_data *inc
>> return config_error_nonbool("include.path");
>> expanded = expand_user_path(path, 0);
>> - if (!expanded)
>> - return error(_("could not expand include path '%s'"), path);
>> + if (!expanded) {
>> + ret = error(_("could not expand include path '%s'"), path);
>> + goto cleanup;
>> + }
>> path = expanded;
>> /*
>> @@ -149,8 +151,10 @@ static int handle_path_include(const char *path, struct config_include_data *inc
>> if (!is_absolute_path(path)) {
>> char *slash;
>> - if (!cf || !cf->path)
>> - return error(_("relative config includes must come from files"));
>> + if (!cf || !cf->path) {
>> + ret = error(_("relative config includes must come from files"));
>> + goto cleanup;
>> + }
>> slash = find_last_dir_sep(cf->path);
>> if (slash)
>> @@ -168,6 +172,7 @@ static int handle_path_include(const char *path, struct config_include_data *inc
>> ret = git_config_from_file(git_config_include, path, inc);
>> inc->depth--;
>> }
>> +cleanup:
>> strbuf_release(&buf);
>> free(expanded);
>> return ret;
>> @@ -1331,8 +1336,10 @@ static int git_default_core_config(const char *var, const char *value, void *cb)
>> if (!strcmp(var, "core.attributesfile"))
>> return git_config_pathname(&git_attributes_file, var, value);
>> - if (!strcmp(var, "core.hookspath"))
>> + if (!strcmp(var, "core.hookspath")) {
>> + UNLEAK(git_hooks_path);
>> return git_config_pathname(&git_hooks_path, var, value);
>> + }
>
> Why is the UNLEAK necessary here? We generally want to limit use of
> UNLEAK to cmd_* functions or direct helpers. git_default_core_config()
> seems generic enough that it could be called from anywhere, and using
> UNLEAK here means we're potentially masking a real leak?
>
> IIUC the leak here happens because:
> - git_hooks_path is a global variable - hence it's unlikely we'd ever
> bother cleaning it up.
> - git_default_core_config() gets called a first time with
> core.hookspath, and we end up allocating new memory into
> git_hooks_path.
> - git_default_core_config() gets called again with core.hookspath,
> and we overwrite git_hooks_path with a new string which leaks
> the string that git_hooks_path used to point to.
>
> So I think the real fix is to free(git_hooks_path) instead of an
> UNLEAK? (Looking at the surrounding code, it looks like the same
> pattern of leak might be repeated for other similar globals - is it
> worth auditing those while we're here?)Good point, I'll fix that.
I was doing this rather blindly to see if I could get this larg batch of tests to pass with some a minimal fixes/whitelisting of some "known bad".
Show 55 quoted lines
>> if (!strcmp(var, "core.bare")) {
>> is_bare_repository_cfg = git_config_bool(var, value);
>> diff --git a/t/t1300-config.sh b/t/t1300-config.sh
>> index 9ff46f3b04..93ad0f4887 100755
>> --- a/t/t1300-config.sh
>> +++ b/t/t1300-config.sh
>> @@ -1050,12 +1050,16 @@ test_expect_success SYMLINKS 'symlink to nonexistent configuration' '
>> test_must_fail git config --file=linktolinktonada --list
>> '
>> -test_expect_success 'check split_cmdline return' "
>> - git config alias.split-cmdline-fix 'echo \"' &&
>> - test_must_fail git split-cmdline-fix &&
>> +test_expect_success 'setup check split_cmdline return' "
>> echo foo > foo &&
>> git add foo &&
>> - git commit -m 'initial commit' &&
>> + git commit -m 'initial commit'
>> +"
>> +
>> +test_expect_success !SANITIZE_LEAK 'check split_cmdline return' "
>> + git config alias.split-cmdline-fix 'echo \"' &&
>> + test_must_fail git split-cmdline-fix &&
>> +
>> git config branch.main.mergeoptions 'echo \"' &&
>> test_must_fail git merge main
>> "
>> @@ -1101,7 +1105,7 @@ test_expect_success 'key sanity-checking' '
>> git config foo."ba =z".bar false
>> '
>> -test_expect_success 'git -c works with aliases of builtins' '
>> +test_expect_success !SANITIZE_LEAK 'git -c works with aliases of builtins' '
>> git config alias.checkconfig "-c foo.check=bar config foo.check" &&
>> echo bar >expect &&
>> git checkconfig >actual &&
>> @@ -1397,7 +1401,7 @@ test_expect_success 'git --config-env with missing value' '
>> grep "invalid config format: config" error
>> '
>> -test_expect_success 'git --config-env fails with invalid
>> parameters' '
>> +test_expect_success !SANITIZE_LEAK 'git --config-env fails with invalid parameters' '
>> test_must_fail git --config-env=foo.flag config --bool foo.flag 2>error &&
>> test_i18ngrep "invalid config format: foo.flag" error &&
>> test_must_fail git --config-env=foo.flag= config --bool foo.flag 2>error &&
>> diff --git a/t/test-lib.sh b/t/test-lib.sh
>> index 9201510e16..98e20950c3 100644
>> --- a/t/test-lib.sh
>> +++ b/t/test-lib.sh
>> @@ -1370,6 +1370,7 @@ maybe_skip_all_sanitize_leak () {
>> add_sanitize_leak_true 't000*'
>> add_sanitize_leak_true 't001*'
>> add_sanitize_leak_true 't006*'
>> + add_sanitize_leak_true 't13*config*'
>> # Blacklist patterns (overrides whitelist)
>> add_sanitize_leak_false 't000[469]*'
>>