zdump -v crashes with 64-bit time_t

Ken Pizzini tz. at explicate.org
Tue Jun 15 04:30:09 UTC 2004


On Mon, Jun 14, 2004 at 08:11:26PM -0700, Ken Pizzini wrote:
> That might work, depending on the local implementation of asctime(),
> but I'd feel more comfortable with a patch that takes care to avoid
> passing a NULL to asctime() in the first place.  Perhaps this patch
> instead?

No, that patch wasn't right either: it did protect the asctime()
calls fine, but it still left zdump.c with many potential dereferences
of NULL localtime() result pointers.  I'm not completely satisfied
with how the code resulting from the patch below handles things,
but at least it now completely avoids dereferencing these NULLs...

(The attached patch is against a fresh copy of zdump.c from tzcode2004a;
i.e., it is *not* incremental to either of the previous two patches
circulated on the list.)

		--Ken Pizzini



--- zdump.c-orig	2004-03-02 06:52:38.000000000 -0800
+++ zdump.c	2004-06-14 21:24:11.735549152 -0700
@@ -1,4 +1,4 @@
-static char	elsieid[] = "@(#)zdump.c	7.31";
+static char	elsieid[] = "@(#)zdump.c	7.32";
 
 /*
 ** This code has been made independent of the rest of the time
@@ -129,6 +129,7 @@
 static size_t	longest;
 static char *	progname;
 static void	show P((char * zone, time_t t, int v));
+static void	complain P((time_t t));
 
 int
 main(argc, argv)
@@ -148,6 +149,7 @@
 	time_t			hibit;
 	struct tm		tm;
 	struct tm		newtm;
+	struct tm		*tmp;
 
 	INITIALIZE(cuttime);
 #if HAVE_GETTEXT - 0
@@ -230,7 +232,12 @@
 		show(argv[i], t, TRUE);
 		t += SECSPERHOUR * HOURSPERDAY;
 		show(argv[i], t, TRUE);
-		tm = *localtime(&t);
+		tmp = localtime(&t);
+		if (tmp == NULL) {
+			complain(t);
+			continue;
+		}
+		tm = *tmp;
 		(void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
 		for ( ; ; ) {
 			if (cutoff != NULL && t >= cuttime)
@@ -240,12 +247,22 @@
 				break;
 			if (newt <= t)
 				break;
-			newtm = *localtime(&newt);
+			tmp = localtime(&newt);
+			if (tmp == NULL) {
+				complain(newt);
+				break;
+			}
+			newtm = *tmp;
 			if (delta(&newtm, &tm) != (newt - t) ||
 				newtm.tm_isdst != tm.tm_isdst ||
 				strcmp(abbr(&newtm), buf) != 0) {
 					newt = hunt(argv[i], t, newt);
-					newtm = *localtime(&newt);
+					tmp = localtime(&newt);
+					if (tmp == NULL) {
+						complain(newt);
+						break;
+					}
+					newtm = *tmp;
 					(void) strncpy(buf, abbr(&newtm),
 						(sizeof buf) - 1);
 			}
@@ -284,9 +301,15 @@
 	time_t		t;
 	struct tm	lotm;
 	struct tm	tm;
+	struct tm	*tmp;
 	static char	loab[MAX_STRING_LENGTH];
 
-	lotm = *localtime(&lot);
+	tmp = localtime(&lot);
+	if (tmp == NULL) {
+		complain(lot);
+		return lot;
+	}
+	lotm = *tmp;
 	(void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
 	while ((hit - lot) >= 2) {
 		t = lot / 2 + hit / 2;
@@ -294,7 +317,12 @@
 			++t;
 		else if (t >= hit)
 			--t;
-		tm = *localtime(&t);
+		tmp = localtime(&t);
+		if (tmp == NULL) {
+			complain(t);
+			return t;
+		}
+		tm = *tmp;
 		if (delta(&tm, &lotm) == (t - lot) &&
 			tm.tm_isdst == lotm.tm_isdst &&
 			strcmp(abbr(&tm), loab) == 0) {
@@ -334,6 +362,14 @@
 	return result;
 }
 
+static char *
+nonnull_asctime(t)
+const struct tm * t;
+{
+	static char null[] = "NULL";
+	return (t == NULL) ? null : asctime(t);
+}
+
 static void
 show(zone, t, v)
 char *	zone;
@@ -344,12 +380,12 @@
 
 	(void) printf("%-*s  ", (int) longest, zone);
 	if (v)
-		(void) printf("%.24s UTC = ", asctime(gmtime(&t)));
+		(void) printf("%.24s UTC = ", nonnull_asctime(gmtime(&t)));
 	tmp = localtime(&t);
-	(void) printf("%.24s", asctime(tmp));
-	if (*abbr(tmp) != '\0')
+	(void) printf("%.24s", nonnull_asctime(tmp));
+	if (tmp != NULL && *abbr(tmp) != '\0')
 		(void) printf(" %s", abbr(tmp));
-	if (v) {
+	if (tmp != NULL && v) {
 		(void) printf(" isdst=%d", tmp->tm_isdst);
 #ifdef TM_GMTOFF
 		(void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
@@ -358,6 +394,13 @@
 	(void) printf("\n");
 }
 
+static void
+complain(t)
+time_t	t;
+{
+	(void) printf("localtime() failed on input %lld\n", (long long)t); /*XXX*/
+}
+
 static char *
 abbr(tmp)
 struct tm *	tmp;



More information about the tz mailing list