diff options
author | Russell Belfer <rb@github.com> | 2013-05-16 01:50:05 +0400 |
---|---|---|
committer | Russell Belfer <rb@github.com> | 2013-05-16 01:50:05 +0400 |
commit | 79ef3be449c9d81dd0b37a30999563aa92e4679e (patch) | |
tree | 5e4e5d47c1fe3823d4fd2b1c794effcc3263b608 | |
parent | f0ab73720a4e7a9b37c901a27519ea65eafeb8a6 (diff) |
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.
-rw-r--r-- | src/diff.c | 6 | ||||
-rw-r--r-- | tests-clar/diff/workdir.c | 25 |
2 files changed, 29 insertions, 2 deletions
diff --git a/src/diff.c b/src/diff.c index f466546bb..d93506984 100644 --- a/src/diff.c +++ b/src/diff.c @@ -747,7 +747,8 @@ static int diff_scan_inside_untracked_dir( } /* 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); /* need to recurse into non-ignored directories */ @@ -769,7 +770,8 @@ static int diff_scan_inside_untracked_dir( } /* 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) break; } diff --git a/tests-clar/diff/workdir.c b/tests-clar/diff/workdir.c index 94fd7165d..18182ea96 100644 --- a/tests-clar/diff/workdir.c +++ b/tests-clar/diff/workdir.c @@ -1220,3 +1220,28 @@ void test_diff_workdir__untracked_directory_scenarios(void) 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); +} |