Commit 79ef3be4 by Russell Belfer

Fix diff crash when last item is untracked dir

When the last item in a diff was an untracked directory that only
contained ignored items, the loop to scan the contents would run
off the end of the iterator and dereference a NULL pointer.  This
includes a test that reproduces the problem and a fix.
parent f0ab7372
...@@ -747,7 +747,8 @@ static int diff_scan_inside_untracked_dir( ...@@ -747,7 +747,8 @@ static int diff_scan_inside_untracked_dir(
} }
/* look for actual untracked file */ /* look for actual untracked file */
while (!diff->pfxcomp(info->nitem->path, git_buf_cstr(&base))) { while (info->nitem != NULL &&
!diff->pfxcomp(info->nitem->path, git_buf_cstr(&base))) {
is_ignored = git_iterator_current_is_ignored(info->new_iter); is_ignored = git_iterator_current_is_ignored(info->new_iter);
/* need to recurse into non-ignored directories */ /* need to recurse into non-ignored directories */
...@@ -769,7 +770,8 @@ static int diff_scan_inside_untracked_dir( ...@@ -769,7 +770,8 @@ static int diff_scan_inside_untracked_dir(
} }
/* finish off scan */ /* finish off scan */
while (!diff->pfxcomp(info->nitem->path, git_buf_cstr(&base))) { while (info->nitem != NULL &&
!diff->pfxcomp(info->nitem->path, git_buf_cstr(&base))) {
if ((error = git_iterator_advance(&info->nitem, info->new_iter)) < 0) if ((error = git_iterator_advance(&info->nitem, info->new_iter)) < 0)
break; break;
} }
......
...@@ -1220,3 +1220,28 @@ void test_diff_workdir__untracked_directory_scenarios(void) ...@@ -1220,3 +1220,28 @@ void test_diff_workdir__untracked_directory_scenarios(void)
git_diff_list_free(diff); git_diff_list_free(diff);
} }
void test_diff_workdir__untracked_directory_comes_last(void)
{
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
git_diff_list *diff = NULL;
g_repo = cl_git_sandbox_init("renames");
cl_git_mkfile("renames/.gitignore", "*.ign\n");
cl_git_pass(p_mkdir("renames/zzz_untracked", 0777));
cl_git_mkfile("renames/zzz_untracked/an.ign", "ignore me please");
cl_git_mkfile("renames/zzz_untracked/skip.ign", "ignore me really");
cl_git_mkfile("renames/zzz_untracked/test.ign", "ignore me now");
opts.context_lines = 3;
opts.interhunk_lines = 1;
opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED;
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
cl_assert(diff != NULL);
git_diff_list_free(diff);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment