From c63d196ece56e6fdbaacb6dac1e7b0cee4ea0b87 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 17 Apr 2014 12:18:57 -0500 Subject: [PATCH] fixup! git tag --contains : avoid stack overflow --- builtin/tag.c | 21 ++++++++++++++------- t/t7004-tag.sh | 9 +++++---- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/builtin/tag.c b/builtin/tag.c index 79c8c28616..40758d40a5 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -73,11 +73,17 @@ static int in_commit_list(const struct commit_list *want, struct commit *c) return 0; } +enum contains_result { + CONTAINS_UNKNOWN = -1, + CONTAINS_NO = 0, + CONTAINS_YES = 1, +}; + /* * Test whether the candidate or one of its parents is contained in the list. * Do not recurse to find out, though, but return -1 if inconclusive. */ -static int contains_test(struct commit *candidate, +static enum contains_result contains_test(struct commit *candidate, const struct commit_list *want) { /* was it previously marked as containing a want commit? */ @@ -121,12 +127,13 @@ static void push_to_stack(struct commit *candidate, struct stack *stack) stack->stack[index].parents = candidate->parents; } -static int contains(struct commit *candidate, const struct commit_list *want) +static enum contains_result contains(struct commit *candidate, + const struct commit_list *want) { struct stack stack = { 0, 0, NULL }; int result = contains_test(candidate, want); - if (result >= 0) + if (result != CONTAINS_UNKNOWN) return result; push_to_stack(candidate, &stack); @@ -136,7 +143,7 @@ static int contains(struct commit *candidate, const struct commit_list *want) struct commit_list *parents = entry->parents; if (!parents) { - commit->object.flags = UNINTERESTING; + commit->object.flags |= UNINTERESTING; stack.nr--; } /* @@ -144,14 +151,14 @@ static int contains(struct commit *candidate, const struct commit_list *want) * therefore contains_test will return a meaningful 0 or 1. */ else switch (contains_test(parents->item, want)) { - case 1: + case CONTAINS_YES: commit->object.flags |= TMP_MARK; stack.nr--; break; - case 0: + case CONTAINS_NO: entry->parents = parents->next; break; - default: + case CONTAINS_UNKNOWN: push_to_stack(parents->item, &stack); break; } diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index edaff13bd4..3f338bd5d1 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1380,10 +1380,11 @@ test_expect_success 'multiple --points-at are OR-ed together' ' test_cmp expect actual ' +test_lazy_prereq BASH 'bash --version' + >expect -# ulimit is a bash builtin; we can rely on that in MinGW, but nowhere else -test_expect_success MINGW '--contains works in a deep repo' ' - ulimit -s 64 +# we require bash for its 'ulimit' builtin +test_expect_success BASH '--contains works in a deep repo' ' i=1 && while test $i -lt 1000 do @@ -1397,7 +1398,7 @@ EOF" done | git fast-import && git checkout master && git tag far-far-away HEAD^ && - git tag --contains HEAD >actual && + bash -c "ulimit -s 64 && git tag --contains HEAD >actual" && test_cmp expect actual '