proposed time zone package changes--core dump avoidance
Below find proposed changes to the time zone package: * asctime.c Set errno to EINVAL and return "??? ??? ?? ??:??:?? ????\n" if asctime_r is called with a NULL struct tm pointer. (Note that asctime_r is called by ctime_r and asctime; asctime is called by ctime.) * localtime.c Set errno to EINVAL and return WRONG if time1 is called with a NULL struct tm pointer; avoid dereference if a NULL struct tm pointer is passed to timelocal, timegm, or timeoff. (Note that time1 is called by mktime, timegm, and timeoff; mktime is called by timelocal.) Barring problems, expect these changes to show up in the ftp package on 2010-02-16 (a day later than usual given a U. S. federal holiday). --ado ------- asctime.c ------- *** /tmp/geta26934 Sat Feb 6 13:23:25 2010 --- /tmp/getb26934 Sat Feb 6 13:23:25 2010 *************** *** 11,17 **** #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)asctime.c 8.2"; #endif /* !defined NOID */ #endif /* !defined lint */ --- 11,17 ---- #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)asctime.c 8.3"; #endif /* !defined NOID */ #endif /* !defined lint */ *************** *** 91,96 **** --- 91,100 ---- char year[INT_STRLEN_MAXIMUM(int) + 2]; char result[MAX_ASCTIME_BUF_SIZE]; + if (timeptr == NULL) { + errno = EINVAL; + return "??? ??? ?? ??:??:?? ????\n"; + } if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK) wn = "???"; else wn = wday_name[timeptr->tm_wday]; ------- localtime.c ------- *** /tmp/geta26952 Sat Feb 6 13:23:25 2010 --- /tmp/getb26952 Sat Feb 6 13:23:25 2010 *************** *** 5,11 **** #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)localtime.c 8.9"; #endif /* !defined NOID */ #endif /* !defined lint */ --- 5,11 ---- #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)localtime.c 8.10"; #endif /* !defined NOID */ #endif /* !defined lint */ *************** *** 1889,1894 **** --- 1889,1898 ---- int types[TZ_MAX_TYPES]; int okay; + if (tmp == NULL) { + errno = EINVAL; + return WRONG; + } if (tmp->tm_isdst > 1) tmp->tm_isdst = 1; t = time2(tmp, funcp, offset, &okay); *************** *** 1960,1966 **** timelocal(tmp) struct tm * const tmp; { ! tmp->tm_isdst = -1; /* in case it wasn't initialized */ return mktime(tmp); } --- 1964,1971 ---- timelocal(tmp) struct tm * const tmp; { ! if (tmp != NULL) ! tmp->tm_isdst = -1; /* in case it wasn't initialized */ return mktime(tmp); } *************** *** 1968,1974 **** timegm(tmp) struct tm * const tmp; { ! tmp->tm_isdst = 0; return time1(tmp, gmtsub, 0L); } --- 1973,1980 ---- timegm(tmp) struct tm * const tmp; { ! if (tmp != NULL) ! tmp->tm_isdst = 0; return time1(tmp, gmtsub, 0L); } *************** *** 1977,1983 **** struct tm * const tmp; const long offset; { ! tmp->tm_isdst = 0; return time1(tmp, gmtsub, offset); } --- 1983,1990 ---- struct tm * const tmp; const long offset; { ! if (tmp != NULL) ! tmp->tm_isdst = 0; return time1(tmp, gmtsub, offset); }
The only issue I have is that it is traditional (not sure if required by the standards or not) to return a writable string from asctime - callers often stick nuls on top of spaces to remove the parts that aren't needed. Returning a "" string directly returns a const (read only memory, possibly) string, what's more, if it is able to be modified, and is modified, then the next time it is returned, the modified version will be. Further, I think asctime_r() is supposed to return its result in the buffer that's passed in, so I think I'd do memcpy(buf, "??? ??? ?? ??:??:?? ????\n"); return buf; rather than return "??? ??? ?? ??:??:?? ????\n"; kre ps: I'm not really convinced the changes to the time*() funcs are worth the bother, there are zillions of library functions that crash if passed a NULL arg - asctime_r() is only special here, as when ctime() calls it, it is called with the result of localtime() which can be null, and aside from calling localtime() and checking the result, there's no real way for the programmer to avoid that one.
Robert Elz said:
The only issue I have is that it is traditional (not sure if required by the standards or not) to return a writable string from asctime
It is my reading of the C99 standard that this is required. -- Clive D.W. Feather | If you lie to the compiler, Email: clive@davros.org | it will get its revenge. Web: http://www.davros.org | - Henry Spencer Mobile: +44 7973 377646
participants (3)
-
Arthur David Olson -
Clive D.W. Feather -
Robert Elz