Moscow ML 2.00 Y2004 bug

After Sat Jan 10 13:37:04 2004 the number of seconds since midnight Jan 1, 1970 exceeded 2^30.

Since Moscow ML uses 31 bit integers only, this could spell trouble in the handling of time values. Actually, this was anticipated in the choice of representation of Time.time values (made in 1994): we subtract 2^30 from the number of seconds, so the int type will not overflow until year 2038.

Unfortunately such foresight was not applied uniformly in the libraries of Moscow ML...

This has the following sad consequences for Moscow ML 2.00 (June 2000):

  1. On all 32-bit platforms, except Moscow ML.Net, Time.toSeconds(Time.now()) will raise Overflow. This is unavoidable. Use Time.toReal instead where possible (this gives fractional seconds).
  2. Time.toString(Time.now()) raises Overflow after 10 Jan 2004. This can be fixed by changing the implementation of fmt in mosml/src/mosmllib/Time.sml:
        fun fmt p t =
            Real.fmt (StringCvt.FIX (SOME (if p > 0 then p else 0))) (toReal t)
    
    This fixes toString also, but changes the behaviour of fmt for negative p (this is required by new Basis spec anyway).
  3. Time.now() + Time.fromReal 0.0 raises Overflow. This can be fixed in mosml/src/mosmllib/Time.sml by performing the computation in reals and convert to int afterwards:
        val op + = fn ({sec=sec1, usec=usec1} : time, {sec=sec2, usec=usec2}) =>
        let val usecs = usec1 + usec2
        in {sec  = trunc(real sec1 - real timebase
                         + real sec2 + real(usecs div 1000000)),
            usec = usecs mod 1000000}
        end
    
  4. In Moscow ML 2.00 for Windows, loading the Timer structure (or invoking Moscow ML with mosml -P full, which loads the Timer structure), will fail. The reason is that function getrutime in mosml/src/runtime/mosml.c equates usr time with system time, but neglects to apply the 2^30 offset mentioned above:
      Field (res, 2) = Val_long (t.time);
      Field (res, 3) = Val_long (((long) t.millitm) * 1000);
      Field (res, 4) = Val_long (t.time);
      Field (res, 5) = Val_long (((long) t.millitm) * 1000);
    
    This code should be fixed as follows:
      Field (res, 2) = Val_long (t.time + TIMEBASE);
      Field (res, 3) = Val_long (((long) t.millitm) * 1000);
      Field (res, 4) = Val_long (t.time + TIMEBASE);
      Field (res, 5) = Val_long (((long) t.millitm) * 1000);
    

I'll make fixed Moscow ML 2.01 sources, tested with Linux, available asap. I haven't been able to test it for Windows, though.

Deep apologies for the trouble caused by this.


Peter Sestoft (sestoft@dina.kvl.dk) 2004-01-12