{"thread":{"id":"29084","subject":"Bug: git bus error (stack blowout)","startedAt":"2011-12-04T22:50:19Z","lastAt":"2011-12-05T04:58:17Z","messageCount":2,"participants":["Venkatesh Srinivas","Nguyen Thai Ngoc Duy"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"180300","messageId":"CAAcG=3NfvYSjhHDNb8aZ=_O4661bV7jkZBpmc77ZVCFDQQdHJw@mail.gmail.com","threadId":"29084","inReplyTo":null,"subject":"Bug: git bus error (stack blowout)","fromName":"Venkatesh Srinivas","fromEmail":"vsrinivas@dragonflybsd.org","sentAt":"2011-12-04T22:50:19Z","receivedAt":"2011-12-04T22:50:19Z","isPatch":false,"sender":{"key":"vsrinivas@dragonflybsd.org","avatar":null},"body":"Hi,\n\nWhen using git 1.7.6.3 from NetBSD's pkgsrc, on this git tree:\nhttp://gitweb.dragonflybsd.org/pkgsrcv2.git, I got a bus error when\nswitching from the pkgsrc-2011q3 branch to the master branch. I have a\ncore file and the git binary if it'd be helpful; it looks like\nmark_parents_uninteresting() was called recursively entirely too many\ntimes (>60,000), originally from prepare_revision_walk(), from\nstat_tracking_info(), from format_tracking_info(),\nupdate_revs_for_switch(), from cmd_checkout().\n\nThanks,\n-- vs;\n"},{"id":"180302","messageId":"20111205045816.GA31766@do","threadId":"29084","inReplyTo":"CAAcG=3NfvYSjhHDNb8aZ=_O4661bV7jkZBpmc77ZVCFDQQdHJw@mail.gmail.com","subject":"Re: Bug: git bus error (stack blowout)","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-12-05T04:58:17Z","receivedAt":"2011-12-05T04:58:17Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Dec 04, 2011 at 05:50:19PM -0500, Venkatesh Srinivas wrote:\n> Hi,\n> \n> When using git 1.7.6.3 from NetBSD's pkgsrc, on this git tree:\n> http://gitweb.dragonflybsd.org/pkgsrcv2.git, I got a bus error when\n> switching from the pkgsrc-2011q3 branch to the master branch. I have a\n> core file and the git binary if it'd be helpful; it looks like\n> mark_parents_uninteresting() was called recursively entirely too many\n> times (>60,000), originally from prepare_revision_walk(), from\n> stat_tracking_info(), from format_tracking_info(),\n> update_revs_for_switch(), from cmd_checkout().\n\nThis patch may fix it for you, although it'd be interesting to\nunderstand how you get into this (I'm still cloning pkgsrcv2.git).\n\n-- 8< --\nSubject: [PATCH] Eliminate recursion in setting/clearing marks in commit list\n\nRecursion in a DAG is generally a bad idea because it could be very\ndeep. Be defensive and avoid recursion in mark_parents_uninteresting()\nand clear_commit_marks().\n\nmark_parents_uninteresting() learns a trick from clear_commit_marks()\nto avoid malloc() in (dorminant) single-parent case.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n commit.c   |   31 ++++++++++++++++++++-----------\n revision.c |   45 +++++++++++++++++++++++++++++----------------\n 2 files changed, 49 insertions(+), 27 deletions(-)\n\ndiff --git a/commit.c b/commit.c\nindex 0775eec..cd19a69 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -423,22 +423,31 @@ struct commit *pop_most_recent_commit(struct commit_list **list,\n \n void clear_commit_marks(struct commit *commit, unsigned int mark)\n {\n-\twhile (commit) {\n-\t\tstruct commit_list *parents;\n+\tstruct commit_list *list = NULL, *l;\n+\tcommit_list_insert(commit, &list);\n+\twhile (list) {\n+\t\tcommit = list->item;\n+\t\tl = list;\n+\t\tlist = list->next;\n+\t\tfree(l);\n \n-\t\tif (!(mark & commit->object.flags))\n-\t\t\treturn;\n+\t\twhile (commit) {\n+\t\t\tstruct commit_list *parents;\n \n-\t\tcommit->object.flags &= ~mark;\n+\t\t\tif (!(mark & commit->object.flags))\n+\t\t\t\tbreak;\n \n-\t\tparents = commit->parents;\n-\t\tif (!parents)\n-\t\t\treturn;\n+\t\t\tcommit->object.flags &= ~mark;\n+\n+\t\t\tparents = commit->parents;\n+\t\t\tif (!parents)\n+\t\t\t\tbreak;\n \n-\t\twhile ((parents = parents->next))\n-\t\t\tclear_commit_marks(parents->item, mark);\n+\t\t\twhile ((parents = parents->next))\n+\t\t\t\tcommit_list_insert(parents->item, &list);\n \n-\t\tcommit = commit->parents->item;\n+\t\t\tcommit = commit->parents->item;\n+\t\t}\n \t}\n }\n \ndiff --git a/revision.c b/revision.c\nindex 0aa3638..8d4069e 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -139,11 +139,32 @@ void mark_tree_uninteresting(struct tree *tree)\n \n void mark_parents_uninteresting(struct commit *commit)\n {\n-\tstruct commit_list *parents = commit->parents;\n+\tstruct commit_list *parents = NULL, *l;\n+\n+\tfor (l = commit->parents; l; l = l->next)\n+\t\tcommit_list_insert(l->item, &parents);\n \n \twhile (parents) {\n \t\tstruct commit *commit = parents->item;\n-\t\tif (!(commit->object.flags & UNINTERESTING)) {\n+\t\tl = parents;\n+\t\tparents = parents->next;\n+\t\tfree(l);\n+\n+\t\twhile (commit) {\n+\t\t\t/*\n+\t\t\t * A missing commit is ok iff its parent is marked\n+\t\t\t * uninteresting.\n+\t\t\t *\n+\t\t\t * We just mark such a thing parsed, so that when\n+\t\t\t * it is popped next time around, we won't be trying\n+\t\t\t * to parse it and get an error.\n+\t\t\t */\n+\t\t\tif (!has_sha1_file(commit->object.sha1))\n+\t\t\t\tcommit->object.parsed = 1;\n+\n+\t\t\tif (commit->object.flags & UNINTERESTING)\n+\t\t\t\tbreak;\n+\n \t\t\tcommit->object.flags |= UNINTERESTING;\n \n \t\t\t/*\n@@ -154,21 +175,13 @@ void mark_parents_uninteresting(struct commit *commit)\n \t\t\t * wasn't uninteresting), in which case we need\n \t\t\t * to mark its parents recursively too..\n \t\t\t */\n-\t\t\tif (commit->parents)\n-\t\t\t\tmark_parents_uninteresting(commit);\n-\t\t}\n+\t\t\tif (!commit->parents)\n+\t\t\t\tbreak;\n \n-\t\t/*\n-\t\t * A missing commit is ok iff its parent is marked\n-\t\t * uninteresting.\n-\t\t *\n-\t\t * We just mark such a thing parsed, so that when\n-\t\t * it is popped next time around, we won't be trying\n-\t\t * to parse it and get an error.\n-\t\t */\n-\t\tif (!has_sha1_file(commit->object.sha1))\n-\t\t\tcommit->object.parsed = 1;\n-\t\tparents = parents->next;\n+\t\t\tfor (l = commit->parents->next; l; l = l->next)\n+\t\t\t\tcommit_list_insert(l->item, &parents);\n+\t\t\tcommit = commit->parents->item;\n+\t\t}\n \t}\n }\n \n-- \n1.7.8.36.g69ee2\n-- 8< --\n-- \nDuy\n"}]}