All of lore.kernel.org
 help / color / mirror / Atom feed
From: "SZEDER Gábor" <szeder.dev@gmail.com>
To: Junio C Hamano <gitster@pobox.com>
Cc: git@vger.kernel.org, "Johannes Sixt" <j6t@kdbg.org>,
	phillip.wood@dunelm.org.uk,
	"brian m. carlson" <sandals@crustytoothpaste.net>,
	"SZEDER Gábor" <szeder.dev@gmail.com>
Subject: [PATCH] name-rev: avoid cutoff timestamp underflow
Date: Tue, 24 Sep 2019 09:32:13 +0200	[thread overview]
Message-ID: <20190924073213.7125-1-szeder.dev@gmail.com> (raw)
In-Reply-To: <20190922180143.25026-1-szeder.dev@gmail.com>

When 'git name-rev' is invoked with commit-ish parameters, it tries to
save some work, and doesn't visit commits older than the committer
date of the oldest given commit minus a one day worth of slop.  Since
our 'timestamp_t' is an unsigned type, this leads to a timestamp
underflow when the committer date of the oldest given commit is within
a day of the UNIX epoch.  As a result the cutoff timestamp ends up
far-far in the future, and 'git name-rev' doesn't visit any commits,
and names each given commit as 'undefined'.

Check whether subtracting the slop from the oldest committer date
would lead to an underflow, and use no cutoff in that case.  We don't
have a TIME_MIN constant, dddbad728c (timestamp_t: a new data type for
timestamps, 2017-04-26) didn't add one, so do it now.

Note that the type of the cutoff timestamp variable used to be signed
before 5589e87fd8 (name-rev: change a "long" variable to timestamp_t,
2017-05-20).  The behavior was still the same even back then, but the
underflow didn't happen when substracting the slop from the oldest
committer date, but when comparing the signed cutoff timestamp with
unsigned committer dates in name_rev().  IOW, this underflow bug is as
old as 'git name-rev' itself.

Helped-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
---
Range-diff:
1:  3bef6bdf7b ! 1:  b053181af9 name-rev: avoid cutoff timestamp underflow
    @@ Commit message
         far-far in the future, and 'git name-rev' doesn't visit any commits,
         and names each given commit as 'undefined'.
     
    -    Check whether substacting the slop from the oldest committer date
    -    would lead to an underflow, and use a 0 as cutoff in that case.  This
    -    way it will handle commits shortly after the epoch even if we were to
    -    switch to a signed 'timestamp_t' (but then we'll have to worry about
    -    signed underflow for very old commits).
    +    Check whether subtracting the slop from the oldest committer date
    +    would lead to an underflow, and use no cutoff in that case.  We don't
    +    have a TIME_MIN constant, dddbad728c (timestamp_t: a new data type for
    +    timestamps, 2017-04-26) didn't add one, so do it now.
     
         Note that the type of the cutoff timestamp variable used to be signed
         before 5589e87fd8 (name-rev: change a "long" variable to timestamp_t,
    @@ Commit message
         unsigned committer dates in name_rev().  IOW, this underflow bug is as
         old as 'git name-rev' itself.
     
    +    Helped-by: Johannes Sixt <j6t@kdbg.org>
         Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
     
      ## builtin/name-rev.c ##
    @@ builtin/name-rev.c
      
     -#define CUTOFF_DATE_SLOP 86400 /* one day */
     +/*
    -+ * One day.  See the 'name a rev close to epoch' test in t6120 when
    ++ * One day.  See the 'name a rev shortly after epoch' test in t6120 when
     + * changing this value
     + */
     +#define CUTOFF_DATE_SLOP 86400
    @@ builtin/name-rev.c: int cmd_name_rev(int argc, const char **argv, const char *pr
     -		cutoff = cutoff - CUTOFF_DATE_SLOP;
     +	if (cutoff) {
     +		/* check for undeflow */
    -+		if (cutoff - CUTOFF_DATE_SLOP < cutoff)
    ++		if (cutoff > TIME_MIN + CUTOFF_DATE_SLOP)
     +			cutoff = cutoff - CUTOFF_DATE_SLOP;
     +		else
    -+			cutoff = 0;
    ++			cutoff = TIME_MIN;
     +	}
      	for_each_ref(name_ref, &data);
      
      	if (transform_stdin) {
     
    + ## git-compat-util.h ##
    +@@ git-compat-util.h: typedef uintmax_t timestamp_t;
    + #define PRItime PRIuMAX
    + #define parse_timestamp strtoumax
    + #define TIME_MAX UINTMAX_MAX
    ++#define TIME_MIN 0
    + 
    + #ifndef PATH_SEP
    + #define PATH_SEP ':'
    +
      ## t/t6120-describe.sh ##
     @@ t/t6120-describe.sh: test_expect_success 'describe complains about missing object' '
      	test_must_fail git describe $ZERO_OID
    @@ t/t6120-describe.sh: test_expect_success 'describe complains about missing objec
     +	# in builtin/name-rev.c.
     +	GIT_COMMITTER_DATE="@1234 +0000" \
     +	git commit -m "committer date shortly after epoch" &&
    -+	near_commit_oid=$(git rev-parse HEAD) &&
    ++	old_commit_oid=$(git rev-parse HEAD) &&
     +
    -+	echo "$near_commit_oid no-timestamp-underflow" >expect &&
    -+	git name-rev $near_commit_oid >actual &&
    ++	echo "$old_commit_oid no-timestamp-underflow" >expect &&
    ++	git name-rev $old_commit_oid >actual &&
     +	test_cmp expect actual
     +'
     +

 builtin/name-rev.c  | 15 ++++++++++++---
 git-compat-util.h   |  1 +
 t/t6120-describe.sh | 15 +++++++++++++++
 3 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index c785fe16ba..b0f0776947 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -9,7 +9,11 @@
 #include "sha1-lookup.h"
 #include "commit-slab.h"
 
-#define CUTOFF_DATE_SLOP 86400 /* one day */
+/*
+ * One day.  See the 'name a rev shortly after epoch' test in t6120 when
+ * changing this value
+ */
+#define CUTOFF_DATE_SLOP 86400
 
 typedef struct rev_name {
 	const char *tip_name;
@@ -481,8 +485,13 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
 		add_object_array(object, *argv, &revs);
 	}
 
-	if (cutoff)
-		cutoff = cutoff - CUTOFF_DATE_SLOP;
+	if (cutoff) {
+		/* check for undeflow */
+		if (cutoff > TIME_MIN + CUTOFF_DATE_SLOP)
+			cutoff = cutoff - CUTOFF_DATE_SLOP;
+		else
+			cutoff = TIME_MIN;
+	}
 	for_each_ref(name_ref, &data);
 
 	if (transform_stdin) {
diff --git a/git-compat-util.h b/git-compat-util.h
index f0d13e4e28..d2e884e46a 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -344,6 +344,7 @@ typedef uintmax_t timestamp_t;
 #define PRItime PRIuMAX
 #define parse_timestamp strtoumax
 #define TIME_MAX UINTMAX_MAX
+#define TIME_MIN 0
 
 #ifndef PATH_SEP
 #define PATH_SEP ':'
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 2b883d8174..45047d0a72 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -424,4 +424,19 @@ test_expect_success 'describe complains about missing object' '
 	test_must_fail git describe $ZERO_OID
 '
 
+test_expect_success 'name-rev a rev shortly after epoch' '
+	test_when_finished "git checkout master" &&
+
+	git checkout --orphan no-timestamp-underflow &&
+	# Any date closer to epoch than the CUTOFF_DATE_SLOP constant
+	# in builtin/name-rev.c.
+	GIT_COMMITTER_DATE="@1234 +0000" \
+	git commit -m "committer date shortly after epoch" &&
+	old_commit_oid=$(git rev-parse HEAD) &&
+
+	echo "$old_commit_oid no-timestamp-underflow" >expect &&
+	git name-rev $old_commit_oid >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.23.0.597.gb58f4577a1


      parent reply	other threads:[~2019-09-24  7:32 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-09-22 18:01 [PATCH] name-rev: avoid cutoff timestamp underflow SZEDER Gábor
2019-09-22 18:57 ` Phillip Wood
2019-09-22 19:53   ` SZEDER Gábor
2019-09-22 21:01     ` Johannes Sixt
2019-09-23  8:37       ` SZEDER Gábor
2019-09-23  9:30         ` Phillip Wood
2019-09-23 19:16         ` Johannes Sixt
2019-09-24  7:21           ` SZEDER Gábor
2019-09-23  1:42 ` brian m. carlson
2019-09-23  8:39   ` SZEDER Gábor
2019-09-24  7:32 ` SZEDER Gábor [this message]

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=20190924073213.7125-1-szeder.dev@gmail.com \
    --to=szeder.dev@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=j6t@kdbg.org \
    --cc=phillip.wood@dunelm.org.uk \
    --cc=sandals@crustytoothpaste.net \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.