From: "Philip Oakley" <philipoakley@iee.org>
To: "Jean-Jacques Lafay" <jeanjacques.lafay@gmail.com>,
<msysgit@googlegroups.com>
Cc: "Git List" <git@vger.kernel.org>
Subject: Re: [PATCH] git tag --contains : avoid stack overflow
Date: Sat, 10 Nov 2012 20:00:28 -0000 [thread overview]
Message-ID: <03ED9D50D1F64467863C051959CFC433@PhilipOakley> (raw)
In-Reply-To: 1352568970-4669-1-git-send-email-jeanjacques.lafay@gmail.com
From: "Jean-Jacques Lafay" <jeanjacques.lafay@gmail.com> Sent: Saturday,
November 10, 2012 5:36 PM
> In large repos, the recursion implementation of contains(commit,
> commit_list)
> may result in a stack overflow. Replace the recursion with a loop to
> fix it.
>
> Signed-off-by: Jean-Jacques Lafay <jeanjacques.lafay@gmail.com>
This is a change to the main git code so it is better to submit it to
the main git list at git@vger.kernel.org (plain text, no HTML, first
post usually has a delay ;-)
It sounds reasonable but others may have opinions and comments.
Have you actually suffered from the stack overflow issue? You only
suggest it as a possibility, rather than a real problem.
Philip
> ---
> builtin/tag.c | 83
> ++++++++++++++++++++++++++++++++++++++++------------------
> t/t7004-tag.sh | 21 +++++++++++++++
> 2 files changed, 78 insertions(+), 26 deletions(-)
>
> diff --git a/builtin/tag.c b/builtin/tag.c
> index 9c3e067..4be67dd 100644
> --- a/builtin/tag.c
> +++ b/builtin/tag.c
> @@ -73,40 +73,71 @@ static int in_commit_list(const struct commit_list
> *want, struct commit *c)
> return 0;
> }
>
> -static int contains_recurse(struct commit *candidate,
> - const struct commit_list *want)
> -{
> - struct commit_list *p;
> -
> - /* was it previously marked as containing a want commit? */
> - if (candidate->object.flags & TMP_MARK)
> - return 1;
> - /* or marked as not possibly containing a want commit? */
> - if (candidate->object.flags & UNINTERESTING)
> - return 0;
> - /* or are we it? */
> - if (in_commit_list(want, candidate))
> - return 1;
> +struct commit_list_list {
> + struct commit *item;
> + struct commit_list *next_item;
> + struct commit_list_list *next;
> +};
>
> - if (parse_commit(candidate) < 0)
> - return 0;
> +static void mark_path(struct commit_list_list *path, int status)
> +{
> + struct commit_list_list *temp;
> + while (path) {
> + path->item->object.flags |= status;
> + temp = path;
> + path = temp->next;
> + free(temp);
> + }
> +}
>
> - /* Otherwise recurse and mark ourselves for future traversals. */
> - for (p = candidate->parents; p; p = p->next) {
> - if (contains_recurse(p->item, want)) {
> - candidate->object.flags |= TMP_MARK;
> +static int contains(struct commit *candidate,
> + const struct commit_list *want)
> +{
> + /* previously implemented with a recursion, but could stack overflow
> in large repos */
> + struct commit_list_list *p, *tmp;
> + p = xmalloc(sizeof(struct commit_list_list));
> + p->item = candidate;
> + p->next_item = NULL;
> + p->next = NULL;
> +
> + while (p) {
> + candidate = p->item;
> +
> + /* is it ok : */
> + /* was it previously marked as containing a want commit? */
> + /* or are we it? */
> + if (candidate->object.flags & TMP_MARK || in_commit_list(want,
> candidate)) {
> + mark_path(p, TMP_MARK);
> return 1;
> }
> + /* is it not ok : */
> + /* was it previously marked as not possibly containing a want
> commit? */
> + /* do we have parents? */
> + if (candidate->object.flags & UNINTERESTING ||
> parse_commit(candidate) < 0 || !candidate->parents) {
> + candidate->object.flags |= UNINTERESTING;
> + /* then backtrack, marking as UNINTERESTING along the way */
> + while (p && !p->next_item) {
> + p->item->object.flags |= UNINTERESTING;
> + tmp = p;
> + p = tmp->next;
> + free(tmp);
> + }
> + if (p) {
> + p->item = p->next_item->item;
> + p->next_item = p->next_item->next;
> + }
> + } else {
> + /* let's check the parents */
> + tmp = xmalloc(sizeof(struct commit_list_list));
> + tmp->item = candidate->parents->item;
> + tmp->next_item = candidate->parents->next;
> + tmp->next = p;
> + p = tmp;
> + }
> }
> - candidate->object.flags |= UNINTERESTING;
> return 0;
> }
>
> -static int contains(struct commit *candidate, const struct
> commit_list *want)
> -{
> - return contains_recurse(candidate, want);
> -}
> -
> static void show_tag_lines(const unsigned char *sha1, int lines)
> {
> int i;
> diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
> index 5189446..196ac54 100755
> --- a/t/t7004-tag.sh
> +++ b/t/t7004-tag.sh
> @@ -1365,4 +1365,25 @@ test_expect_success 'multiple --points-at are
> OR-ed together' '
> test_cmp expect actual
> '
>
> +# what about a deep repo ?
> +
> +>expect
> +test_expect_success '--contains works in a deep repo' '
> + i=1
> + while test $i -lt 40000
> + do
> + echo "commit refs/heads/master
> +committer A U Thor <author@example.com> $((1000000000 + $i * 100))
> +0200
> +data <<EOF
> +commit #$i
> +EOF"
> + test $i == 1 && echo "from refs/heads/master^0"
> + i=$(($i + 1))
> + done | git fast-import
> + git checkout master
> + git tag far-far-away HEAD^
> + git tag --contains HEAD >actual &&
> + test_cmp expect actual
> +'
> +
> test_done
> --
> 1.8.0.msysgit.0.1.geed93bd.dirty
>
> --
--
*** Please reply-to-all at all times ***
*** (do not pretend to know who is subscribed and who is not) ***
*** Please avoid top-posting. ***
The msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.
You received this message because you are subscribed to the Google
Groups "msysGit" group.
To post to this group, send email to msysgit@googlegroups.com
To unsubscribe from this group, send email to
msysgit+unsubscribe@googlegroups.com
For more options, and view previous threads, visit this group at
http://groups.google.com/group/msysgit?hl=en_US?hl=en
next parent reply other threads:[~2012-11-10 20:00 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <1352568970-4669-1-git-send-email-jeanjacques.lafay@gmail.com>
2012-11-10 20:00 ` Philip Oakley [this message]
2012-11-10 21:13 ` [PATCH] git tag --contains : avoid stack overflow Jean-Jacques Lafay
2012-11-10 21:33 ` Pat Thoyts
2012-11-11 16:46 ` René Scharfe
2012-11-11 16:54 ` Jeff King
2012-11-11 23:10 ` Johannes Schindelin
2012-11-12 22:27 ` Jean-Jacques Lafay
2012-11-12 23:14 ` Jeff King
2012-11-13 1:16 ` Johannes Schindelin
2012-11-13 3:46 ` [msysGit] " Jeff King
2012-11-13 4:01 ` Johannes Schindelin
2012-11-13 4:05 ` Jeff King
2012-11-13 4:52 ` Johannes Schindelin
2012-11-13 4:51 ` Junio C Hamano
2012-11-13 6:08 ` Jeff King
2014-04-16 14:15 Stepan Kasal
2014-04-16 15:46 ` Jeff King
2014-04-17 17:31 ` Johannes Schindelin
2014-04-17 21:32 ` Jeff King
2014-04-17 21:52 ` Johannes Schindelin
2014-04-17 21:58 ` Jeff King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=03ED9D50D1F64467863C051959CFC433@PhilipOakley \
--to=philipoakley@iee.org \
--cc=git@vger.kernel.org \
--cc=jeanjacques.lafay@gmail.com \
--cc=msysgit@googlegroups.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox