{"thread":{"id":"38282","subject":"[PATCH v4] for-each-ref: Always check stat_tracking_info()'s return value.","startedAt":"2015-01-05T09:58:55Z","lastAt":"2015-01-06T23:51:04Z","messageCount":2,"participants":["Raphael Kubo da Costa","Junio C Hamano"],"isPatch":true,"patchVersion":4,"patchTotal":null},"messages":[{"id":"254289","messageId":"1420451935-6008-1-git-send-email-raphael.kubo.da.costa@intel.com","threadId":"38282","inReplyTo":null,"subject":"[PATCH v4] for-each-ref: Always check stat_tracking_info()'s return value.","fromName":"Raphael Kubo da Costa","fromEmail":"raphael.kubo.da.costa@intel.com","sentAt":"2015-01-05T09:58:55Z","receivedAt":"2015-01-05T09:58:55Z","isPatch":true,"sender":{"key":"raphael.kubo.da.costa@intel.com","avatar":null},"body":"The code handling %(upstream:track) and %(upstream:trackshort) assumed\nit always had a valid branch that had been sanitized earlier in\npopulate_value(), and thus did not check the return value of the call to\nstat_tracking_info().\n\nWhile there is indeed some sanitization code that basically corresponds\nto stat_tracking_info() returning 0 (no base branch set), the function\ncan also return -1 when the base branch did exist but has since then\nbeen deleted.\n\nIn this case, num_ours and num_theirs had undefined values and a call to\n`git for-each-ref --format=\"%(upstream:track)\"` could print spurious\nvalues such as\n\n  [behind -111794512]\n  [ahead 38881640, behind 5103867]\n\neven for repositories with one single commit.\n\nWe now properly verify stat_tracking_info()'s return value and do not\nprint anything if it returns -1. This behavior also matches the\ndocumentation (\"has no effect if the ref does not have tracking\ninformation associated with it\").\n\nHelped-by: Eric Sunshine <sunshine@sunshineco.com>\nHelped-by: Jeff King <peff@peff.net>\nSigned-off-by: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com>\n---\nv4: Use Jeff's suggestion and simplify the test case and making it\n    easier to understand what is actually being tested.\n\n builtin/for-each-ref.c  | 11 +++++++++--\n t/t6300-for-each-ref.sh | 14 ++++++++++++++\n 2 files changed, 23 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex 603a90e..52e6323 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -717,7 +717,10 @@ static void populate_value(struct refinfo *ref)\n \t\t\t\t starts_with(name, \"upstream\")) {\n \t\t\t\tchar buf[40];\n \n-\t\t\t\tstat_tracking_info(branch, &num_ours, &num_theirs);\n+\t\t\t\tif (stat_tracking_info(branch, &num_ours,\n+\t\t\t\t\t\t       &num_theirs) != 1)\n+\t\t\t\t\tcontinue;\n+\n \t\t\t\tif (!num_ours && !num_theirs)\n \t\t\t\t\tv->s = \"\";\n \t\t\t\telse if (!num_ours) {\n@@ -735,7 +738,11 @@ static void populate_value(struct refinfo *ref)\n \t\t\t} else if (!strcmp(formatp, \"trackshort\") &&\n \t\t\t\t   starts_with(name, \"upstream\")) {\n \t\t\t\tassert(branch);\n-\t\t\t\tstat_tracking_info(branch, &num_ours, &num_theirs);\n+\n+\t\t\t\tif (stat_tracking_info(branch, &num_ours,\n+\t\t\t\t\t\t\t&num_theirs) != 1)\n+\t\t\t\t\tcontinue;\n+\n \t\t\t\tif (!num_ours && !num_theirs)\n \t\t\t\t\tv->s = \"=\";\n \t\t\t\telse if (!num_ours)\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex bda354c..dcee7a0 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -335,6 +335,20 @@ test_expect_success 'Check that :track[short] cannot be used with other atoms' '\n '\n \n cat >expected <<EOF\n+\n+\n+EOF\n+\n+test_expect_success 'Check that :track[short] works when upstream is invalid' '\n+\ttest_when_finished \"git config branch.master.merge refs/heads/master\" &&\n+\tgit config branch.master.merge refs/heads/does-not-exist &&\n+\tgit for-each-ref \\\n+\t\t--format=\"%(upstream:track)$LF%(upstream:trackshort)\" \\\n+\t\trefs/heads > actual &&\n+\ttest_cmp expected actual\n+'\n+\n+cat >expected <<EOF\n $(git rev-parse --short HEAD)\n EOF\n \n-- \n2.1.4\n"},{"id":"254382","messageId":"xmqqsifnmpsn.fsf@gitster.dls.corp.google.com","threadId":"38282","inReplyTo":"1420451935-6008-1-git-send-email-raphael.kubo.da.costa@intel.com","subject":"Re: [PATCH v4] for-each-ref: Always check stat_tracking_info()'s return value.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-01-06T23:51:04Z","receivedAt":"2015-01-06T23:51:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com> writes:\n\n> The code handling %(upstream:track) and %(upstream:trackshort) assumed\n> it always had a valid branch that had been sanitized earlier in\n> populate_value(), and thus did not check the return value of the call to\n> stat_tracking_info().\n>\n> While there is indeed some sanitization code that basically corresponds\n> to stat_tracking_info() returning 0 (no base branch set), the function\n> can also return -1 when the base branch did exist but has since then\n> been deleted.\n>\n> In this case, num_ours and num_theirs had undefined values and a call to\n> `git for-each-ref --format=\"%(upstream:track)\"` could print spurious\n> values such as\n>\n>   [behind -111794512]\n>   [ahead 38881640, behind 5103867]\n>\n> even for repositories with one single commit.\n>\n> We now properly verify stat_tracking_info()'s return value and do not\n> print anything if it returns -1. This behavior also matches the\n> documentation (\"has no effect if the ref does not have tracking\n> information associated with it\").\n>\n> Helped-by: Eric Sunshine <sunshine@sunshineco.com>\n> Helped-by: Jeff King <peff@peff.net>\n> Signed-off-by: Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com>\n> ---\n> v4: Use Jeff's suggestion and simplify the test case and making it\n>     easier to understand what is actually being tested.\n\nNicely done, indeed.  Thanks all.  Will queue with some cosmetic\ntweaks.\n"}]}