From ed6a7ba60e87e1fd4b5c504d82c348e8dc415117 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 6 Oct 2003 22:46:24 +0000 Subject: 19168: Various problems with size of buffers and pointer usage in ztrftime --- Src/Modules/datetime.c | 15 +++++------ Src/prompt.c | 11 +++++--- Src/utils.c | 68 +++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 75 insertions(+), 19 deletions(-) (limited to 'Src') diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c index d10274f0d..383f748b5 100644 --- a/Src/Modules/datetime.c +++ b/Src/Modules/datetime.c @@ -35,10 +35,9 @@ static int bin_strftime(char *nam, char **argv, Options ops, int func) { int bufsize, x; - char *endptr = NULL, *buffer = NULL; + char *endptr = NULL, *buffer; time_t secs; struct tm *t; - int size; secs = (time_t)strtoul(argv[1], &endptr, 10); if (secs == ULONG_MAX) { @@ -51,15 +50,17 @@ bin_strftime(char *nam, char **argv, Options ops, int func) t = localtime(&secs); bufsize = strlen(argv[0]) * 2; + buffer = zalloc(bufsize); - for (x=1;x<4;x++) { - buffer = zrealloc(buffer, bufsize * x); - size = ztrftime(buffer, bufsize * x, argv[0], t); - if (size) x = 4; + for (x=0; x < 4; x++) { + if (ztrftime(buffer, bufsize, argv[0], t)) + break; + buffer = zrealloc(buffer, bufsize *= 2); } printf("%s\n", buffer); - + zfree(buffer, bufsize); + return 0; } diff --git a/Src/prompt.c b/Src/prompt.c index ac96ad340..dc31eddb6 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -500,18 +500,23 @@ putpromptchar(int doprint, int endchar) tmfmt = "%m/%d/%y"; break; case 'D': - if (fm[1] == '{') /*}*/ { + if (fm[1] == '{' /*}*/) { for (ss = fm + 2; *ss && *ss != /*{*/ '}'; ss++) if(*ss == '\\' && ss[1]) ss++; dd = tmfmt = tmbuf = zalloc(ss - fm); - for (ss = fm + 2; *ss && *ss != /*{*/ '}'; ss++) { + for (ss = fm + 2; *ss && *ss != /*{*/ '}'; + ss++) { if(*ss == '\\' && ss[1]) ss++; *dd++ = *ss; } *dd = 0; fm = ss - !*ss; + if (!*tmfmt) { + free(tmbuf); + continue; + } } else tmfmt = "%y-%m-%d"; break; @@ -523,7 +528,7 @@ putpromptchar(int doprint, int endchar) tm = localtime(&timet); for(t0=80; ; t0*=2) { addbufspc(t0); - if(ztrftime(bp, t0, tmfmt, tm) != t0) + if (ztrftime(bp, t0, tmfmt, tm)) break; } bp += strlen(bp); diff --git a/Src/utils.c b/Src/utils.c index 56230fddb..536fe13e0 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1685,20 +1685,42 @@ spckword(char **s, int hist, int cmd, int ask) } } +/* + * Helper for ztrftime. Called with a pointer to the length left + * in the buffer, and a new string length to decrement from that. + * Returns 0 if the new length fits, 1 otherwise. We assume a terminating + * NUL and return 1 if that doesn't fit. + */ + +/**/ +static int +ztrftimebuf(int *bufsizeptr, int decr) +{ + if (*bufsizeptr <= decr) + return 1; + *bufsizeptr -= decr; + return 0; +} + +/* + * Like the system function, this returns the number of characters + * copied, not including the terminating NUL. This may be zero + * if the string didn't fit. + */ + /**/ mod_export int ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm) { - int hr12; + int hr12, decr; #ifndef HAVE_STRFTIME static char *astr[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; static char *estr[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; -#else - char *origbuf = buf; #endif + char *origbuf = buf; char tmp[3]; @@ -1707,6 +1729,14 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm) while (*fmt) if (*fmt == '%') { fmt++; + /* + * Assume this format will take up at least two + * characters. Not always true, but if that matters + * we are so close to the edge it's not a big deal. + * Fix up some longer cases specially when we get to them. + */ + if (ztrftimebuf(&bufsize, 2)) + return 0; switch (*fmt++) { case 'd': *buf++ = '0' + tm->tm_mday / 10; @@ -1734,9 +1764,10 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm) if (hr12 == 0) hr12 = 12; if (hr12 > 9) - *buf++ = '1'; + *buf++ = '1'; else if (fmt[-1] == 'l') - *buf++ = ' '; + *buf++ = ' '; + *buf++ = '0' + (hr12 % 10); break; case 'm': @@ -1755,11 +1786,20 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm) *buf++ = '0' + (tm->tm_year / 10) % 10; *buf++ = '0' + tm->tm_year % 10; break; + case '\0': + /* Guard against premature end of string */ + *buf++ = '%'; + fmt--; + break; #ifndef HAVE_STRFTIME case 'a': + if (ztrftimebuf(&bufsize, strlen(astr[tm->tm_wday]) - 2)) + return 0; strucpy(&buf, astr[tm->tm_wday]); break; case 'b': + if (ztrftimebuf(&bufsize, strlen(estr[tm->tm_mon]) - 2)) + return 0; strucpy(&buf, estr[tm->tm_mon]); break; case 'p': @@ -1772,17 +1812,27 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm) *buf++ = fmt[-1]; #else default: + /* + * Remember we've already allowed for two characters + * in the accounting in bufsize (but nowhere else). + */ *buf = '\0'; tmp[1] = fmt[-1]; - strftime(buf, bufsize - strlen(origbuf), tmp, tm); - buf += strlen(buf); + if (!strftime(buf, bufsize + 2, tmp, tm)) + return 0; + decr = strlen(buf); + buf += decr; + bufsize -= decr - 2; #endif break; } - } else + } else { + if (ztrftimebuf(&bufsize, 1)) + return 0; *buf++ = *fmt++; + } *buf = '\0'; - return 0; + return buf - origbuf; } /**/ -- cgit 1.4.1