DRAFT: Y2038 Proofness Design


History

Revision 24 was reviewed on the libc-alpha mailing list.

Scope

The intent of this page is to serve as a central point for describing the Y2038 proofness design.

Y2038 proofness means that application calls to glibc-provided function should never return wrong results when UTC times outside -231..231-1 seconds from the Unix Epoch are involved.

Useful Definitions

Goals

Constraints

There are a number of constraints which dictate the direction of the design. They are either definite or debatable. Debatable design preclusions should be finalized before this design document leaves DRAFT.

Definite

Debatable

This sounds like something totally unrelated, but the underlying idea is to not multiply the possible combinations.

IOW, this design does not aim at trying to fix existing 32-bit time support at all; any fix to the Y2038 problem will be within new 64-bit time support.

On some architectures, time_t is already 64-bit wide even though it still contains a signed value ranging from -2**31 to (2**31)-1. Introducing 64-bit support should only change the range from -2**63 to (2**63)-1.

API changes

This sections describes the API changes required for supporting Y2038 in GLIBC.

Y2038-sensitive GLIBC date/time APIs

This section lists all time-related API symbols based on section 21 of the glibc manual (https://www.gnu.org/software/libc/manual/html_node/Date-and-Time.html#Date-and-Time) and indicates which ones are sensitive to Y2038 and which ones are not.

"Y2038-sentive" means the symbol might fail to handle calendar times beyond Y2038; whether it actually fails or succeeds will be determined by analyzing the implementation.

"Y2038-insensitive" symbols are définitely not susceptible to Y2038-related bugs.

Function

Y2038-sensitive?

double difftime (time_t time1, time_t time0)

No, assuming time_t is Y2038-proof (see note 1)

struct timeval { time_t tv_sec; long int tv_usec; } 

YES, due to time_t tv_sec

struct timespec { time_t tv_sec; long int tv_nsec; } 

YES, due to time_t tv_sec

clock_t clock(void)

No, return value is not clock time in seconds since the epoch but CPU time in clock ticks

struct tms { clock_t tms_utime; clock_t tms_stime; clock_t tms_cutime; clock_t tms_cstime; } 

No, as all members are processor time in clock ticks

clock_t times(struct tms *buffer)

No, as its argument is not Y20338-sensitive

time_t

YES on 32-bit systems, No on 64-bit systems (see note 2)

time_t time (time_t *result)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

int stime (const time_t *newtime)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 4)

struct timezone { int tz_minuteswest; int tz_dsttime; } 

No

int gettimeofday (struct timeval *tp, struct timezone *tzp)

YES, due to struct timeval *tp (see notes 2 and 3)

int settimeofday (const struct timeval *tp, const struct timezone *tzp)

YES, due to struct timeval *tp (see notes 2 and 4)

int adjtime (const struct timeval *delta, struct timeval *olddelta)

No, as the struct timeval contains a small value

int adjtimex (struct timex *timex)

No, as the struct timex contains a small value

struct tm { int tm_sec; int tm_min; ... } 

No, as the structure contains no count of seconds from epoch

struct tm * localtime (const time_t *time)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

struct tm * localtime_r (const time_t *time, struct tm *resultp)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

struct tm * gmtime (const time_t *time)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

struct tm * gmtime_r (const time_t *time, struct tm *resultp)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

time_t mktime (struct tm *brokentime)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 4)

time_t timelocal (struct tm *brokentime)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 4)

time_t timegm (struct tm *brokentime)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 4)

struct ntptimeval { struct timeval time; long int maxerror; long int esterror; } 

YES, due to struct timeval time

ntp_gettime (struct ntptimeval *tptr)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

struct timex { ... struct timeval time; ... } 

YES, due to struct timeval time

int ntp_adjtime (struct timex *tptr)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

char * asctime (const struct tm *brokentime)

No, as struct tm is not Y2038-sensitive

char * asctime_r (const struct tm *brokentime, char *buffer)

No, as struct tm is not Y2038-sensitive

char * ctime (const time_t *time)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

char * ctime_r (const time_t *time, char *buffer)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

size_t strftime (char *s, size_t size, const char *template, const struct tm *brokentime)

No, as struct tm is not Y2038-sensitive

size_t wcsftime (wchar_t *s, size_t size, const wchar_t *template, const struct tm *brokentime)

No, as struct tm is not Y2038-sensitive

char * strptime (const char *s, const char *fmt, struct tm *tp)

No, as struct tm is not Y2038-sensitive

struct tm * getdate (const char *string)

No, as struct tm is not Y2038-sensitive

int getdate_r (const char *string, struct tm *tp)

No, as struct tm is not Y2038-sensitive

struct itimerval { struct timeval it_interval; struct timeval it_value; } 

No, as the struct timeval fields hold intervals, not epoch-based times

int setitimer (int which, const struct itimerval *new, struct itimerval *old)

| No, as struct itimerval is not Y2038-sentitive

int getitimer (int which, struct itimerval *old)

No, as struct itimerval is not Y2038-sentitive

unsigned int alarm (unsigned int seconds)

No, as the input is an interval, not an epoch-based time

unsigned int sleep (unsigned int seconds)

No, as the input is an interval, not an epoch-based time

int nanosleep (const struct timespec *requested_time, struct timespec *remaining)

No, as the struct timespec fields hold intervals, not epoch-based times

Notes:

  1. The result is limited in precision because of its double type. However this is not Y2038-related.

  2. time_t is defined as a long int, which on a 64-bit system, has no practical limit. This extends to struct timeval and struct timespec.

  3. Regardless of the time_t size, the function may not return a time_t value beyond Y2038.

  4. Regardless of the time_t size, the function may not accept an time_t input value beyond Y2038.

Other Y2038-sensitive GLIBC APIs

Some other areas of the GLIB API use time_t directly or as a member of struct timeval and struct timespec, for instance struct stat which is used in the stat() function. The following table lists these.

Function

Y2038-sensitive?

Section 14.9.9 - File times

struct utimbuf { time_t actime; time_t modtime; } 

YES, as time_t is Y2038-sensitive

int utime (const char *filename, const struct utimbuf *times)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

int utimes (const char *filename, const struct timeval tvp[2])

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

int lutimes (const char *filename, const struct timeval tvp[2])

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

int futimes (int fd, const struct timeval tvp[2])

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

Section 22.1

struct rusage { struct timeval ru_utime; struct timeval ru_stime; ... } 

YES, as struct_timeval is Y2038-sensitive

int getrusage (int processes, struct rusage *rusage)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

struct vtimes { struct timeval vm_utime; struct timeval vm_stime; ... } 

YES, as struct_timeval is Y2038-sensitive

int vtimes (struct vtimes *current, struct vtimes *child)

YES on 32-bit systems, TBC on 64-bit systems (see notes 2 & 3)

(to be completed)

Y2038-sensitive IOCTLs

Some Linux IOCTLs are Y2038-sensitive. However, at the GLIBC level, none of the IOCTLs argument types described are time_t or derived from it.

Changes to Y2038-sensitive APIs

ABI changes

On 64-bits systems, time_t is already 64 bit wide even though its range is limited to -231..231-1. Therefore, 64-bit applications built for 32-bit time support should be able to directly use the 64-bit time ABI, and a 64-bit GLIBC needs only provide 64-bit time support.

(applications might have internal bugs in their handling of time_t values, but this is not a GLIBC concern; as long as applications just receive {{{time_t values]]] from GLIBC and pass them back to it, the existing "64-bit-time_t ABI" can be used for actual 64-bit-time support.)

On 32-bit systems, the size of time_t will be different for 32-bit and 64-bit time support. Consequently, structures containing time_t will have different sizes and field offsets. Therefore, the 64-bit-time ABI will be incompatible with the 32-bit-time ABI. In order to support both ABIs, and especially in order to remain backward-compatible with existing application binaries, a 32-bit GLIBC must always provide 32-bit time support through the same set of symbols, whether or not it also supports 64-bit time (through new symbols).

Implementation

This allows user code to check, by verifying whether __USE_TIME_BITS64 is defined once glibc headers are #included, that they are using a GLIBC which actually supports 64-bit time (or claims to).

For instance, providing 64-bit time support for the time() function would result in the following:

Support for non-64-bit-time kernels

This will allow 64-bit-time applications to run on older kernels until (around) 2038 or until these kernels are retired, whichever happens first.

Symbol versioning appears unnecessary so far.

tv_usec: to be addressed. May need GLIBC to convert structs.

tv_nsec size: to be addressed, needs to be long as per Posix / C11.

References

[1] http://git.kernel.org/cgit/linux/kernel/git/arnd/playground.git/log/?h=y2038-syscalls

Annex: Linux kernel 64-bit time support

This support is work in progress; the following is a bona fide attempt to provide some background information on it.

Resources

Modified and added syscalls

Modified:

Added:

None: Y2038ProofnessDesign (last edited 2016-01-28 19:06:07 by AlbertAribaud)