[tz] [PROPOSED PATCH 3/4] * zdump.c: Avoid crashes on unlikely integer overflows.
Paul Eggert
eggert at cs.ucla.edu
Thu Aug 21 21:43:25 UTC 2014
(longest): Now int, since it can't exceed INT_MAX.
(sumsize, settimezone): New functions.
(main): Don't let 'longest' exceed INT_MAX. Use settimezone.
(show): Remove no-longer-necessary cast that formerly had undefined
behavior if 'longest' exceeded INT_MAX.
---
zdump.c | 82 ++++++++++++++++++++++++++++++++++++++++++++---------------------
1 file changed, 56 insertions(+), 26 deletions(-)
diff --git a/zdump.c b/zdump.c
index 08323c1..f5a4dff 100644
--- a/zdump.c
+++ b/zdump.c
@@ -207,7 +207,7 @@ static time_t const absolute_max_time =
((time_t) -1 < 0
? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1))
: -1);
-static size_t longest;
+static int longest;
static char * progname;
static bool warned;
static bool errout;
@@ -239,6 +239,54 @@ is_alpha(char a)
}
}
+/* Return A + B, exiting if the result would overflow. */
+static size_t
+sumsize(size_t a, size_t b)
+{
+ size_t sum = a + b;
+ if (sum < a) {
+ fprintf(stderr, "%s: size overflow\n", progname);
+ exit(EXIT_FAILURE);
+ }
+ return sum;
+}
+
+/* Set the global time zone to VAL, exiting on memory allocation failure. */
+static void
+settimezone(char const *val)
+{
+ static char **fakeenv;
+ char **env = fakeenv;
+ char *oldstorage = env ? env[0] : 0;
+ char *env0;
+ if (! env) {
+ char **e = environ;
+ int to;
+
+ while (*e++)
+ continue;
+ env = malloc(sumsize(sizeof *environ,
+ (e - environ) * sizeof *environ));
+ if (! env) {
+ perror(progname);
+ exit(EXIT_FAILURE);
+ }
+ to = 1;
+ for (e = environ; (env[to] = *e); e++)
+ to += strncmp(*e, "TZ=", 3) != 0;
+ }
+ env0 = malloc(sumsize(sizeof "TZ=", strlen(val)));
+ if (! env0) {
+ perror(progname);
+ exit(EXIT_FAILURE);
+ }
+ strcpy(env0, "TZ=");
+ strcat(env0, val);
+ env[0] = env0;
+ environ = fakeenv = env;
+ free(oldstorage);
+}
+
#ifndef TYPECHECK
#define my_localtime localtime
#else /* !defined TYPECHECK */
@@ -345,7 +393,6 @@ main(int argc, char *argv[])
register char * cuttimes;
register time_t cutlotime;
register time_t cuthitime;
- register char ** fakeenv;
time_t now;
time_t t;
time_t newt;
@@ -446,33 +493,16 @@ main(int argc, char *argv[])
}
now = time(NULL);
longest = 0;
- for (i = optind; i < argc; ++i)
- if (strlen(argv[i]) > longest)
- longest = strlen(argv[i]);
- {
- register int from;
- register int to;
-
- for (i = 0; environ[i] != NULL; ++i)
- continue;
- fakeenv = malloc((i + 2) * sizeof *fakeenv);
- if (fakeenv == NULL
- || (fakeenv[0] = malloc(longest + 4)) == NULL) {
- perror(progname);
- return EXIT_FAILURE;
- }
- to = 0;
- strcpy(fakeenv[to++], "TZ=");
- for (from = 0; environ[from] != NULL; ++from)
- if (strncmp(environ[from], "TZ=", 3) != 0)
- fakeenv[to++] = environ[from];
- fakeenv[to] = NULL;
- environ = fakeenv;
+ for (i = optind; i < argc; i++) {
+ size_t arglen = strlen(argv[i]);
+ if (longest < arglen)
+ longest = arglen < INT_MAX ? arglen : INT_MAX;
}
+
for (i = optind; i < argc; ++i) {
static char buf[MAX_STRING_LENGTH];
- strcpy(&fakeenv[0][3], argv[i]);
+ settimezone(argv[i]);
if (! (vflag | Vflag)) {
show(argv[i], now, false);
continue;
@@ -646,7 +676,7 @@ show(char *zone, time_t t, bool v)
{
register struct tm * tmp;
- printf("%-*s ", (int) longest, zone);
+ printf("%-*s ", longest, zone);
if (v) {
tmp = gmtime(&t);
if (tmp == NULL) {
--
1.9.1
More information about the tz
mailing list