[tz] [PATCH 2/8] Avoid arithmetic overflow in ‘hunt’

Paul Eggert eggert at cs.ucla.edu
Wed Mar 24 03:58:47 UTC 2021


* zdump.c (hunt): Fix arithmetic overflow bug when hunting near
timestamp extrema; HIT - LOT can overflow.  The old code attempted to
work around this by assuming wraparound arithmetic, but that
assumption is not safe (the C standard says behavior is undefined) and
the workarounds weren’t even correct anyway for large negative times.
---
 zdump.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/zdump.c b/zdump.c
index dcad817..464a334 100644
--- a/zdump.c
+++ b/zdump.c
@@ -654,7 +654,6 @@ hunt(timezone_t tz, char *name, time_t lot, time_t hit)
 	static char *		loab;
 	static size_t		loabsize;
 	char const *		ab;
-	time_t			t;
 	struct tm		lotm;
 	struct tm		tm;
 	bool lotm_ok = my_localtime_rz(tz, &lot, &lotm) != NULL;
@@ -663,15 +662,16 @@ hunt(timezone_t tz, char *name, time_t lot, time_t hit)
 	if (lotm_ok)
 	  ab = saveabbr(&loab, &loabsize, &lotm);
 	for ( ; ; ) {
-		time_t diff = hit - lot;
-		if (diff < 2)
+		/* T = average of LOT and HIT, rounding down.
+		   Avoid overflow, even on oddball C89 platforms
+		   where / rounds down and TIME_T_MIN == -TIME_T_MAX
+		   so lot / 2 + hit / 2 might overflow.  */
+		time_t t = (lot / 2
+			    - ((lot % 2 + hit % 2) < 0)
+			    + ((lot % 2 + hit % 2) == 2)
+			    + hit / 2);
+		if (t == lot)
 			break;
-		t = lot;
-		t += diff / 2;
-		if (t <= lot)
-			++t;
-		else if (t >= hit)
-			--t;
 		tm_ok = my_localtime_rz(tz, &t, &tm) != NULL;
 		if (lotm_ok & tm_ok
 		    ? (delta(&tm, &lotm) == t - lot
-- 
2.27.0



More information about the tz mailing list