[tz] [PROPOSED PATCH 4/4] zdump: Don't silently truncate too-long abbreviations.

Paul Eggert eggert at cs.ucla.edu
Thu Aug 21 21:43:26 UTC 2014


Instead, allocate a longer buffer, exiting if memory is exhausted.
* zdump.c (abbrev, abbrevsize, loab, loabsize): New static vars.
(saveabbr): New function.
(main, loab): Use the new function and variables.
(abbr): Arg is now a pointer-to-const, for saveabbr.
---
 zdump.c | 48 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 37 insertions(+), 11 deletions(-)

diff --git a/zdump.c b/zdump.c
index f5a4dff..76b3453 100644
--- a/zdump.c
+++ b/zdump.c
@@ -212,7 +212,7 @@ static char *	progname;
 static bool	warned;
 static bool	errout;
 
-static char *abbr(struct tm *);
+static char *abbr(struct tm const *);
 static intmax_t	delta(struct tm *, struct tm *) ATTRIBUTE_PURE;
 static void dumptime(struct tm const *);
 static time_t hunt(char *, time_t, time_t);
@@ -359,6 +359,36 @@ abbrok(const char *const abbrp, const char *const zone)
 	warned = errout = true;
 }
 
+/* Extensible buffers for time zone abbreviations of the current and
+   low-boundary probes.  */
+static char *abbrev;
+static size_t abbrevsize;
+static char *loab;
+static size_t loabsize;
+
+/* Save into *BUF (of size *BUFALLOC) the time zone abbreviation of TMP.
+   Exit on memory allocation failure.  */
+static void
+saveabbr(char **buf, size_t *bufalloc, struct tm const *tmp)
+{
+  char const *ab = abbr(tmp);
+  size_t ablen = strlen(ab);
+  if (*bufalloc <= ablen) {
+    free(*buf);
+
+    /* Make the new buffer at least twice as long as the old,
+       to avoid O(N**2) behavior on repeated calls.  */
+    *bufalloc = sumsize(*bufalloc, ablen + 1);
+
+    *buf = malloc(*bufalloc);
+    if (! *buf) {
+      perror(progname);
+      exit(EXIT_FAILURE);
+    }
+  }
+  strcpy(*buf, ab);
+}
+
 static void
 close_file(FILE *stream)
 {
@@ -500,8 +530,6 @@ main(int argc, char *argv[])
 	}
 
 	for (i = optind; i < argc; ++i) {
-		static char	buf[MAX_STRING_LENGTH];
-
 		settimezone(argv[i]);
 		if (! (vflag | Vflag)) {
 			show(argv[i], now, false);
@@ -519,7 +547,7 @@ main(int argc, char *argv[])
 		tmp = my_localtime(&t);
 		if (tmp != NULL) {
 			tm = *tmp;
-			strncpy(buf, abbr(&tm), (sizeof buf) - 1);
+			saveabbr(&abbrev, &abbrevsize, &tm);
 		}
 		for ( ; ; ) {
 			newt = (t < absolute_max_time - SECSPERDAY / 2
@@ -533,14 +561,13 @@ main(int argc, char *argv[])
 			if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
 				(delta(&newtm, &tm) != (newt - t) ||
 				newtm.tm_isdst != tm.tm_isdst ||
-				strcmp(abbr(&newtm), buf) != 0)) {
+				strcmp(abbr(&newtm), abbrev) != 0)) {
 					newt = hunt(argv[i], t, newt);
 					newtmp = localtime(&newt);
 					if (newtmp != NULL) {
 						newtm = *newtmp;
-						strncpy(buf,
-							abbr(&newtm),
-							(sizeof buf) - 1);
+						saveabbr(&abbrev, &abbrevsize,
+							 &newtm);
 					}
 			}
 			t = newt;
@@ -612,12 +639,11 @@ hunt(char *name, time_t lot, time_t hit)
 	register struct tm *	lotmp;
 	struct tm		tm;
 	register struct tm *	tmp;
-	char			loab[MAX_STRING_LENGTH];
 
 	lotmp = my_localtime(&lot);
 	if (lotmp != NULL) {
 		lotm = *lotmp;
-		strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
+		saveabbr(&loab, &loabsize, &lotm);
 	}
 	for ( ; ; ) {
 		time_t diff = hit - lot;
@@ -705,7 +731,7 @@ show(char *zone, time_t t, bool v)
 }
 
 static char *
-abbr(struct tm *tmp)
+abbr(struct tm const *tmp)
 {
 	register char *	result;
 	static char	nada;
-- 
1.9.1



More information about the tz mailing list