Commit fb23d05f by Carlos Martín Nieto

revwalk: make mark_unintersting use a loop

Using a recursive function can blow the stack when dealing with long
histories. Use a loop instead to limit the call chain depth.

This fixes #1223.
parent 51a5e133
...@@ -63,6 +63,8 @@ GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size) ...@@ -63,6 +63,8 @@ GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size)
#define git_array_last(a) ((a).size ? &(a).ptr[(a).size - 1] : NULL) #define git_array_last(a) ((a).size ? &(a).ptr[(a).size - 1] : NULL)
#define git_array_pop(a) ((a).size ? &(a).ptr[--(a).size] : NULL)
#define git_array_get(a, i) (((i) < (a).size) ? &(a).ptr[(i)] : NULL) #define git_array_get(a, i) (((i) < (a).size) ? &(a).ptr[(i)] : NULL)
#define git_array_size(a) (a).size #define git_array_size(a) (a).size
......
...@@ -41,28 +41,50 @@ git_commit_list_node *git_revwalk__commit_lookup( ...@@ -41,28 +41,50 @@ git_commit_list_node *git_revwalk__commit_lookup(
return commit; return commit;
} }
static void mark_uninteresting(git_commit_list_node *commit) static int mark_uninteresting(git_commit_list_node *commit)
{ {
unsigned short i; unsigned short i;
git_array_t(git_commit_list_node *) pending = GIT_ARRAY_INIT;
git_commit_list_node **tmp;
assert(commit); assert(commit);
commit->uninteresting = 1; git_array_alloc(pending);
GITERR_CHECK_ARRAY(pending);
/* This means we've reached a merge base, so there's no need to walk any more */ do {
if ((commit->flags & (RESULT | STALE)) == RESULT) commit->uninteresting = 1;
return;
/* This means we've reached a merge base, so there's no need to walk any more */
if ((commit->flags & (RESULT | STALE)) == RESULT) {
tmp = git_array_pop(pending);
commit = tmp ? *tmp : NULL;
continue;
}
for (i = 0; i < commit->out_degree; ++i)
if (!commit->parents[i]->uninteresting) {
git_commit_list_node **node = git_array_alloc(pending);
GITERR_CHECK_ALLOC(node);
*node = commit->parents[i];
}
tmp = git_array_pop(pending);
commit = tmp ? *tmp : NULL;
} while (git_array_size(pending) > 0);
for (i = 0; i < commit->out_degree; ++i) git_array_clear(pending);
if (!commit->parents[i]->uninteresting)
mark_uninteresting(commit->parents[i]); return 0;
} }
static int process_commit(git_revwalk *walk, git_commit_list_node *commit, int hide) static int process_commit(git_revwalk *walk, git_commit_list_node *commit, int hide)
{ {
int error; int error;
if (hide) if (hide && mark_uninteresting(commit) < 0)
mark_uninteresting(commit); return -1;
if (commit->seen) if (commit->seen)
return 0; return 0;
......
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