Subject: Re: bug#39944: 27.0.90; JIT Stealth timer errors

From: Eli Zaretskii <[email-masked]>
Date: Fri, 06 Mar 2020 18:11:14 +0200

> Date: Fri, 06 Mar 2020 12:16:07 +0200
> From: Eli Zaretskii <[email-masked]>
> 
> > Additional information which is probably related: the *Message* buffer
> > shows this from time to time:
> > 
> >   run-at-time: Invalid time format
> >   ([nil 24162 5043 0 5 display-time-event-handler nil nil 0] [nil 24162 5046 46875 nil undo-auto--boundary-timer nil nil 0] [nil 24162 5098 187500 60 battery-update-handler nil nil 0] [nil 24162 54768 140625 86400 run-hooks (midnight-hook) nil 0])
> 
> This message comes from this fragment of run-at-time:
> 
>   (or (consp time)
>       (error "Invalid time format"))
> 
> I guess this means the problem is general with timers, not specific to
> JIT Stealth.

The problem is in run-at-time, here:

  ;; Handle numbers as relative times in seconds.
  (if (numberp time)
      (setq time (timer-relative-time nil time)))

This is assumed to always produce time in list format, but at least on
my system (32-bit build --with-wide-int) it sometimes produces an
integer.  I instrumented run-at-time and got a backtrace that clearly
shows that run-at-time was called with the first arg zero, and the
value returned from time-relative-time was a (large) integer.  Looking
at time_arith, I see that this could happen when HZ is computed to be
the number 1.  I tried to figure out why this happens, but quickly got
lost (the comments in that part of the code can really use some
enhancement; they currently seem to target only experts in both time
handling and GMP: many macros whose names don't explain what they do,
and plethora of calls to libgmp functions that have no comments
whatsoever).

Assuming that an integer value is legitimate in that place, here's the
change I propose; since making that change locally, I didn't have even
a single error of this kind:

diff --git a/lisp/emacs-lisp/timer.el b/lisp/emacs-lisp/timer.el
index 74a9495..e61c1a6 100644
--- a/lisp/emacs-lisp/timer.el
+++ b/lisp/emacs-lisp/timer.el
@@ -353,8 +353,10 @@ run-at-time
       (setq time (timer-next-integral-multiple-of-time (current-time) repeat)))
 
   ;; Handle numbers as relative times in seconds.
-  (if (numberp time)
-      (setq time (timer-relative-time nil time)))
+  (when (numberp time)
+    (setq time (timer-relative-time nil time))
+    (or (consp time)
+        (setq time (time-convert time 'list))))
 
   ;; Handle relative times like "2 hours 35 minutes"
   (if (stringp time)