bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Emacs current-time-string core dump on 64-bit hosts


From: Paul Eggert
Subject: Re: Emacs current-time-string core dump on 64-bit hosts
Date: Mon, 27 Mar 2006 14:00:15 -0800
User-agent: Gnus/5.1007 (Gnus v5.10.7) Emacs/21.4 (gnu/linux)

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Paul Eggert <eggert@CS.UCLA.EDU>
>> Date: Sun, 19 Mar 2006 15:44:25 -0800
>> 
>>      * lib-src/ntlib.c (sys_ctime): Remove, since Emacs never calls
>>      ctime any more.
>>      * lib-src/ntlib.h (ctime): Likewise.
>>      * src/w32.c (sys_ctime): Likewise.
>>      * src/s/ms-w32.h (ctime): Likewise.
>
> Please don't remove these from the w32 files (I explained earlier why).

I've left them alone but I'd like to follow up on this, since a
comment or two would be helpful even if we don't change the code.

Here's your earlier explanation:

   I wouldn't remove these: the functions are almost trivial wrappers
   around the library version, and someone could try using ctime in the
   future (in a different context), in which case they will hit the
   Windows library bug again.

But this explanation is problematic, at least in the context of an
Emacs that is intended to be portable to 64-bit hosts.  Here's why.
The ntlib.c and w32 wrappers do this:

  char *str = (char *) ctime (t);
  return (str ? str : "Sun Jan 01 00:00:00 1970");

That is, the wrappers cause 'ctime' to always return a non-NULL pointer.
But any future Emacs code that uses ctime on an arbitrary time stamp
cannot expect ctime to always return a non-null pointer.  Even glibc
ctime (a "nice" ctime, which always has well-defined behavior) returns
NULL in some cases, e.g., if given a time stamp equal to 2**56.

Any future Emacs code that attempts to use ctime on an arbitrary time
stamp and an arbitrary POSIX platform will have to do something like
this, to be safe:

  struct tm *tm = localtime (&timestamp);
  if (! (tm && -999 - 1900 <= tm->tm_year && tm->tm_year <= 9999 - 1900))
    fatal ("current time is out of range");
  p = asctime (tm);

Even if Emacs can assume a "nice" ctime (a big assumption), it'd still
have to do something like this:

  p = ctime (&timestamp);
  if (! p)
    fatal ("current time is out of range");

But notice that neither code snippet needs the w32-style wrapper; so
the wrapper can be safely removed.

I suppose Emacs code might in theory want to invoke ctime in a context
where the time stamp is known to be in range, presumably because the
equivalent of the abovementioned tests have already been done.  But
this is pretty unlikely, because if the tests have already been done,
then the code already has the translated time.

If these arguments convince you, then let's please install the
above-mentioned change to the w32 files, which removes the ctime
wrappers.  If not, then I suggest the following change instead.  It
inserts a comment that attempts to explain the current situation, as I
understand it.  It also corrects a minor problem with the wrappers:
they return "Sun Jan 01 00:00:00 1970" for out-of-range time stamps,
which is wrong for two reasons.  First, 1970-01-01 was a Thursday, not
a Sunday.  Second, the day of the month should be space-padded, not
zero-padded.

There is a similar issue for src/mac.c and mac/inc/s-mac.h but I'd
like to get the W32 issues out of the way first.

2006-03-27  Paul Eggert  <eggert@cs.ucla.edu>

        * lib-src/ntlib.c (sys_ctime): Add a comment explaining why this
        wrapper is still here, even though Emacs doesn't use it.
        Correct the substitute string from "Sun Jan 01 00:00:00 1970"
        to "Thu Jan  1 00:00:00 1970".
        * src/w32.c (sys_ctime): Likewise.

*** lib-src/ntlib.c     6 Feb 2006 11:28:28 -0000       1.13
--- lib-src/ntlib.c     27 Mar 2006 21:47:52 -0000
*************** fchown (int fd, int uid, int gid)
*** 190,201 ****
  
  /* Place a wrapper around the MSVC version of ctime.  It returns NULL
     on network directories, so we handle that case here.
!    (Ulrich Leodolter, 1/11/95).  */
  char *
  sys_ctime (const time_t *t)
  {
    char *str = (char *) ctime (t);
!   return (str ? str : "Sun Jan 01 00:00:00 1970");
  }
  
  FILE *
--- 190,208 ----
  
  /* Place a wrapper around the MSVC version of ctime.  It returns NULL
     on network directories, so we handle that case here.
!    (Ulrich Leodolter, 1/11/95).
! 
!    ctime has undefined behavior with out-of-range time stamps so Emacs
!    no longer uses it.  However, a future version of Emacs might find a
!    use for ctime, in a context where time stamps are known to be in a
!    safe range for POSIX (i.e., from 1970 through 9999), but not for NT
!    (1970 through 3000), so this wrapper has not been removed from the
!    Emacs source code.  */
  char *
  sys_ctime (const time_t *t)
  {
    char *str = (char *) ctime (t);
!   return (str ? str : "Thu Jan  1 00:00:00 1970");
  }
  
  FILE *
*** src/w32.c   27 Feb 2006 02:07:37 -0000      1.100
--- src/w32.c   27 Mar 2006 21:47:52 -0000
*************** gettimeofday (struct timeval *tv, struct
*** 1327,1338 ****
  
  /* Place a wrapper around the MSVC version of ctime.  It returns NULL
     on network directories, so we handle that case here.
!    (Ulrich Leodolter, 1/11/95).  */
  char *
  sys_ctime (const time_t *t)
  {
    char *str = (char *) ctime (t);
!   return (str ? str : "Sun Jan 01 00:00:00 1970");
  }
  
  /* Emulate sleep...we could have done this with a define, but that
--- 1327,1345 ----
  
  /* Place a wrapper around the MSVC version of ctime.  It returns NULL
     on network directories, so we handle that case here.
!    (Ulrich Leodolter, 1/11/95).
! 
!    ctime has undefined behavior with out-of-range time stamps so Emacs
!    no longer uses it.  However, a future version of Emacs might find a
!    use for ctime, in a context where time stamps are known to be in a
!    safe range for POSIX (i.e., from 1970 through 9999), but not for W32
!    (1970 through 3000), so this wrapper has not been removed from the
!    Emacs source code.  */
  char *
  sys_ctime (const time_t *t)
  {
    char *str = (char *) ctime (t);
!   return (str ? str : "Thu Jan  1 00:00:00 1970");
  }
  
  /* Emulate sleep...we could have done this with a define, but that






reply via email to

[Prev in Thread] Current Thread [Next in Thread]