diff --git a/ChangeLog b/ChangeLog index 430decf37a..73ea01bf52 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2005-10-14 Ulrich Drepper + [BZ #1460] + * time/asctime.c (asctime_internal): New function, derived from + asctime_r. Takes additional parameter which is the buffer length. + Use snprintf instead sprintf, if it overflows, fail. + (asctime_r): Call asctime_internal with 26 as buffer length. + (asctime): Call asctime_internal with length of internal buffer. + * time/Makefile (tests): Add bug-asctime_r. + * time/bug-asctime_r.c: New file. + [BZ #1459] * time/asctime.c (__asctime_r): Check for tm_year computation to overflow and fail in this case. diff --git a/time/Makefile b/time/Makefile index cb4837c183..734f0d5373 100644 --- a/time/Makefile +++ b/time/Makefile @@ -35,7 +35,7 @@ distribute := datemsk tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \ tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \ - tst-mktime3 tst-strptime2 bug-asctime + tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r include ../Rules diff --git a/time/asctime.c b/time/asctime.c index 8ac4aa76a4..db29dffb2f 100644 --- a/time/asctime.c +++ b/time/asctime.c @@ -31,17 +31,9 @@ extern const struct locale_data _nl_C_LC_TIME attribute_hidden; static const char format[] = "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n"; static char result[ 3+1+ 3+1+20+1+20+1+20+1+20+1+20+1 + 1]; -/* Returns a string of the form "Day Mon dd hh:mm:ss yyyy\n" - which is the representation of TP in that form. */ -char * -asctime (const struct tm *tp) -{ - return __asctime_r (tp, result); -} -libc_hidden_def (asctime) -char * -__asctime_r (const struct tm *tp, char *buf) +static char * +asctime_internal (const struct tm *tp, char *buf, size_t buflen) { if (tp == NULL) { @@ -58,19 +50,42 @@ __asctime_r (const struct tm *tp, char *buf) a buffer size would be passed. */ if (__builtin_expect (tp->tm_year > INT_MAX - 1900, 0)) { + eoverflow: __set_errno (EOVERFLOW); return NULL; } - if (sprintf (buf, format, - (tp->tm_wday < 0 || tp->tm_wday >= 7 ? - "???" : ab_day_name (tp->tm_wday)), - (tp->tm_mon < 0 || tp->tm_mon >= 12 ? - "???" : ab_month_name (tp->tm_mon)), - tp->tm_mday, tp->tm_hour, tp->tm_min, - tp->tm_sec, 1900 + tp->tm_year) < 0) + int n = snprintf (buf, buflen, format, + (tp->tm_wday < 0 || tp->tm_wday >= 7 ? + "???" : ab_day_name (tp->tm_wday)), + (tp->tm_mon < 0 || tp->tm_mon >= 12 ? + "???" : ab_month_name (tp->tm_mon)), + tp->tm_mday, tp->tm_hour, tp->tm_min, + tp->tm_sec, 1900 + tp->tm_year); + if (n < 0) return NULL; + if (n >= buflen) + goto eoverflow; return buf; } + + +/* Like asctime, but write result to the user supplied buffer. The + buffer is only guaranteed to be 26 bytes in length. */ +char * +__asctime_r (const struct tm *tp, char *buf) +{ + return asctime_internal (tp, buf, 26); +} weak_alias (__asctime_r, asctime_r) + + +/* Returns a string of the form "Day Mon dd hh:mm:ss yyyy\n" + which is the representation of TP in that form. */ +char * +asctime (const struct tm *tp) +{ + return asctime_internal (tp, result, sizeof (result)); +} +libc_hidden_def (asctime) diff --git a/time/bug-asctime.c b/time/bug-asctime.c index 7204e1b2fe..0b04b475a8 100644 --- a/time/bug-asctime.c +++ b/time/bug-asctime.c @@ -19,6 +19,7 @@ do_test (void) result = 1; } char buf[1000]; + errno = 0; s = asctime_r (tp, buf); if (s != NULL || errno != EOVERFLOW) { diff --git a/time/bug-asctime_r.c b/time/bug-asctime_r.c new file mode 100644 index 0000000000..2579a6a3b0 --- /dev/null +++ b/time/bug-asctime_r.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include + + +static int +do_test (void) +{ + int result = 0; + time_t t = time (NULL); + struct tm *tp = localtime (&t); + tp->tm_year = 10000 - 1900; + char buf[1000]; + errno = 0; + char *s = asctime_r (tp, buf); + if (s != NULL || errno != EOVERFLOW) + { + puts ("asctime_r did not fail correctly"); + result = 1; + } + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c"