{"thread":{"id":"62483","subject":"[PATCH v2] builtin/difftool: intialize some hashmap variables","startedAt":"2024-11-12T16:43:18Z","lastAt":"2024-11-12T16:43:18Z","messageCount":1,"participants":["Simon Marchi"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"507138","messageId":"20241112162320.818091-1-simon.marchi@polymtl.ca","threadId":"62483","inReplyTo":null,"subject":"[PATCH v2] builtin/difftool: intialize some hashmap variables","fromName":"Simon Marchi","fromEmail":"simon.marchi@polymtl.ca","sentAt":"2024-11-12T16:22:57Z","receivedAt":"2024-11-12T16:43:18Z","isPatch":true,"sender":{"key":"simon.marchi@polymtl.ca","avatar":null},"body":"From: Simon Marchi <simon.marchi@efficios.com>\n\nWhen running a dir-diff command that produces no diff, variables\n`wt_modified` and `tmp_modified` are used while uninitialized, causing:\n\n    $ /home/smarchi/src/git/git-difftool --dir-diff master\n    free(): invalid pointer\n    [1]    334004 IOT instruction (core dumped)  /home/smarchi/src/git/git-difftool --dir-diff master\n    $ valgrind --track-origins=yes /home/smarchi/src/git/git-difftool --dir-diff master\n    ...\n    Invalid free() / delete / delete[] / realloc()\n       at 0x48478EF: free (vg_replace_malloc.c:989)\n       by 0x422CAC: hashmap_clear_ (hashmap.c:208)\n       by 0x283830: run_dir_diff (difftool.c:667)\n       by 0x284103: cmd_difftool (difftool.c:801)\n       by 0x238E0F: run_builtin (git.c:484)\n       by 0x2392B9: handle_builtin (git.c:750)\n       by 0x2399BC: cmd_main (git.c:921)\n       by 0x356FEF: main (common-main.c:64)\n     Address 0x1ffefff180 is on thread 1's stack\n     in frame #2, created by run_dir_diff (difftool.c:358)\n    ...\n\nIf taking any `goto finish` path before these variables are initialized,\n`hashmap_clear_and_free()` operates on uninitialized data, sometimes\ncausing a crash.\n\nThis regression was introduced in 7f795a1715 (builtin/difftool: plug\nseveral trivial memory leaks, 2024-09-26).\n\nFix it by initializing those variables with the `HASHMAP_INIT` macro.\n\nAdd a test comparing the main branch to itself, resulting in no diff.\n\nSigned-off-by: Simon Marchi <simon.marchi@efficios.com>\nCc: Junio C Hamano <gitster@pobox.com>\nCc: René Scharfe <l.s.r@web.de>\nCc: Taylor Blau <me@ttaylorr.com>\nCc: Patrick Steinhardt <ps@pks.im>\n---\n\nNew in v2:\n\n - Use the `HASHMAP_INIT` macro instead of zero-initializing the\n   variables.\n - Improve an existing test to cover this case.\n\n---\n builtin/difftool.c  | 6 ++----\n t/t7800-difftool.sh | 4 ++++\n 2 files changed, 6 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/difftool.c b/builtin/difftool.c\nindex ca1b0890659b..40e971e2259d 100644\n--- a/builtin/difftool.c\n+++ b/builtin/difftool.c\n@@ -376,7 +376,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \tstruct checkout lstate, rstate;\n \tint err = 0;\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n-\tstruct hashmap wt_modified, tmp_modified;\n+\tstruct hashmap wt_modified = HASHMAP_INIT(path_entry_cmp, NULL);\n+\tstruct hashmap tmp_modified = HASHMAP_INIT(path_entry_cmp, NULL);\n \tint indices_loaded = 0;\n \n \tworkdir = repo_get_work_tree(the_repository);\n@@ -601,9 +602,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,\n \t * in the common case of --symlinks and the difftool updating\n \t * files through the symlink.\n \t */\n-\thashmap_init(&wt_modified, path_entry_cmp, NULL, wtindex.cache_nr);\n-\thashmap_init(&tmp_modified, path_entry_cmp, NULL, wtindex.cache_nr);\n-\n \tfor (i = 0; i < wtindex.cache_nr; i++) {\n \t\tstruct hashmap_entry dummy;\n \t\tconst char *name = wtindex.cache[i]->name;\ndiff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh\nindex f67b9345b8a0..fcaa1748e4a8 100755\n--- a/t/t7800-difftool.sh\n+++ b/t/t7800-difftool.sh\n@@ -666,6 +666,10 @@ run_dir_diff_test 'difftool --dir-diff syncs worktree without unstaged change' '\n \ttest_cmp expect file\n '\n \n+run_dir_diff_test 'difftool --dir-diff with no diff' '\n+\tgit difftool -d main main\n+'\n+\n write_script modify-file <<\\EOF\n echo \"new content\" >file\n EOF\n\nbase-commit: b31fb630c0fc6869a33ed717163e8a1210460d94\n-- \n2.47.0\n\n"}]}