Skip to content

Commit db69bf6

Browse files
ahuntgitster
authored andcommitted
revision: free remainder of old commit list in limit_list
limit_list() iterates over the original revs->commits list, and consumes many of its entries via pop_commit. However we might stop iterating over the list early (e.g. if we realise that the rest of the list is uninteresting). If we do stop iterating early, list will be pointing to the unconsumed portion of revs->commits - and we need to free this list to avoid a leak. (revs->commits itself will be an invalid pointer: it will have been free'd during the first pop_commit.) However the list pointer is later reused to iterate over our new list, but only for the limiting_can_increase_treesame() branch. We therefore need to introduce a new variable for that branch - and while we're here we can rename the original list to original_list as that makes its purpose more obvious. This leak was found while running t0090. It's not likely to be very impactful, but it can happen quite early during some checkout invocations, and hence seems to be worth fixing: Direct leak of 16 byte(s) in 1 object(s) allocated from: #0 0x49a85d in malloc ../projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3 #1 0x9ac084 in do_xmalloc wrapper.c:41:8 #2 0x9ac05a in xmalloc wrapper.c:62:9 #3 0x7175d6 in commit_list_insert commit.c:540:33 #4 0x71800f in commit_list_insert_by_date commit.c:604:9 #5 0x8f8d2e in process_parents revision.c:1128:5 #6 0x8f2f2c in limit_list revision.c:1418:7 #7 0x8f210e in prepare_revision_walk revision.c:3577:7 #8 0x514170 in orphaned_commit_warning builtin/checkout.c:1185:6 #9 0x512f05 in switch_branches builtin/checkout.c:1250:3 #10 0x50f8de in checkout_branch builtin/checkout.c:1646:9 #11 0x50ba12 in checkout_main builtin/checkout.c:2003:9 #12 0x5086c0 in cmd_checkout builtin/checkout.c:2055:8 #13 0x4cd91d in run_builtin git.c:467:11 #14 0x4cb5f3 in handle_builtin git.c:719:3 #15 0x4ccf47 in run_argv git.c:808:4 #16 0x4caf49 in cmd_main git.c:939:19 #17 0x69dc0e in main common-main.c:52:11 #18 0x7faaabd0e349 in __libc_start_main (/lib64/libc.so.6+0x24349) Indirect leak of 48 byte(s) in 3 object(s) allocated from: #0 0x49a85d in malloc ../projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3 #1 0x9ac084 in do_xmalloc wrapper.c:41:8 #2 0x9ac05a in xmalloc wrapper.c:62:9 #3 0x717de6 in commit_list_append commit.c:1609:35 #4 0x8f1f9b in prepare_revision_walk revision.c:3554:12 #5 0x514170 in orphaned_commit_warning builtin/checkout.c:1185:6 #6 0x512f05 in switch_branches builtin/checkout.c:1250:3 #7 0x50f8de in checkout_branch builtin/checkout.c:1646:9 #8 0x50ba12 in checkout_main builtin/checkout.c:2003:9 #9 0x5086c0 in cmd_checkout builtin/checkout.c:2055:8 #10 0x4cd91d in run_builtin git.c:467:11 #11 0x4cb5f3 in handle_builtin git.c:719:3 #12 0x4ccf47 in run_argv git.c:808:4 #13 0x4caf49 in cmd_main git.c:939:19 #14 0x69dc0e in main common-main.c:52:11 #15 0x7faaabd0e349 in __libc_start_main (/lib64/libc.so.6+0x24349) Signed-off-by: Andrzej Hunt <ajrhunt@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 68ffe09 commit db69bf6

File tree

1 file changed

+10
-7
lines changed

1 file changed

+10
-7
lines changed

revision.c

+10-7
Original file line numberDiff line numberDiff line change
@@ -1393,20 +1393,20 @@ static int limit_list(struct rev_info *revs)
13931393
{
13941394
int slop = SLOP;
13951395
timestamp_t date = TIME_MAX;
1396-
struct commit_list *list = revs->commits;
1396+
struct commit_list *original_list = revs->commits;
13971397
struct commit_list *newlist = NULL;
13981398
struct commit_list **p = &newlist;
13991399
struct commit_list *bottom = NULL;
14001400
struct commit *interesting_cache = NULL;
14011401

14021402
if (revs->ancestry_path) {
1403-
bottom = collect_bottom_commits(list);
1403+
bottom = collect_bottom_commits(original_list);
14041404
if (!bottom)
14051405
die("--ancestry-path given but there are no bottom commits");
14061406
}
14071407

1408-
while (list) {
1409-
struct commit *commit = pop_commit(&list);
1408+
while (original_list) {
1409+
struct commit *commit = pop_commit(&original_list);
14101410
struct object *obj = &commit->object;
14111411
show_early_output_fn_t show;
14121412

@@ -1415,11 +1415,11 @@ static int limit_list(struct rev_info *revs)
14151415

14161416
if (revs->max_age != -1 && (commit->date < revs->max_age))
14171417
obj->flags |= UNINTERESTING;
1418-
if (process_parents(revs, commit, &list, NULL) < 0)
1418+
if (process_parents(revs, commit, &original_list, NULL) < 0)
14191419
return -1;
14201420
if (obj->flags & UNINTERESTING) {
14211421
mark_parents_uninteresting(commit);
1422-
slop = still_interesting(list, date, slop, &interesting_cache);
1422+
slop = still_interesting(original_list, date, slop, &interesting_cache);
14231423
if (slop)
14241424
continue;
14251425
break;
@@ -1452,14 +1452,17 @@ static int limit_list(struct rev_info *revs)
14521452
* Check if any commits have become TREESAME by some of their parents
14531453
* becoming UNINTERESTING.
14541454
*/
1455-
if (limiting_can_increase_treesame(revs))
1455+
if (limiting_can_increase_treesame(revs)) {
1456+
struct commit_list *list = NULL;
14561457
for (list = newlist; list; list = list->next) {
14571458
struct commit *c = list->item;
14581459
if (c->object.flags & (UNINTERESTING | TREESAME))
14591460
continue;
14601461
update_treesame(revs, c);
14611462
}
1463+
}
14621464

1465+
free_commit_list(original_list);
14631466
revs->commits = newlist;
14641467
return 0;
14651468
}

0 commit comments

Comments
 (0)