#907264 glibc's strptime does not handle %z and %Z as expected

Package:
libc6
Source:
glibc
Description:
GNU C Library: Shared libraries
Submitter:
Ian Jackson
Date:
2022-03-09 15:45:06 UTC
Severity:
normal
#907264#5
Date:
2018-08-25 16:14:57 UTC
From:
To:
1. faketime does not properly validate the supplied advanced timestamp
   format:
      $ faketime -f '2018-06-26 09:00:03+02:00' date -R
      Tue, 26 Jun 2018 09:00:03 +0100
      $ date -R -d '2018-06-26 09:00:03+02:00'
      Tue, 26 Jun 2018 08:00:03 +0100
      $

2. There is no way to specify a time which does not depend on the
   timezone in force.  This is quite awkward, because there are some
   times which, in some timezones, cannot be represented in the
   offered `advanced timestamp format'.

      $ TZ=Europe/London date -d @$(( 1540683000 + 3600 * 0 )) -R
      Sun, 28 Oct 2018 00:30:00 +0100
      $ TZ=Europe/London date -d @$(( 1540683000 + 3600 * 1 )) -R
      Sun, 28 Oct 2018 01:30:00 +0100
      $ TZ=Europe/London date -d @$(( 1540683000 + 3600 * 2 )) -R
      Sun, 28 Oct 2018 01:30:00 +0000
      $ TZ=Europe/London date -d @$(( 1540683000 + 3600 * 3 )) -R
      Sun, 28 Oct 2018 02:30:00 +0000
      $ TZ=Europe/London faketime -f '2018-10-28 01:30:00' date -R
      Sun, 28 Oct 2018 01:30:00 +0000
      $

   The problem is that
     "2018-10-28 01:30:00 London time"
   occurs twice, at both of
     Sun, 28 Oct 2018 01:30:00 +0100 = Sun, 28 Oct 2018 00:30:00 +0000
   and
     Sun, 28 Oct 2018 01:30:00 +0000

   faketime makes it impossible to specify the former.

   This can be worked around by saving and restoring TZ:
     env TZ=UTC faketime -f <something> env TZ="$TZ" <actual command...>

I suggest that these bugs be fixed by interpreting a numeric timezone
offset in RFC3339 format, as shown above.  This should be done for
both the absolute frozen time, and the start-at timestamp.

Thanks,
Ian.

#907264#10
Date:
2018-08-25 19:44:04 UTC
From:
To:
Ian,

thanks for the detailed report, which is clearly to confirm.

libfaketime internally relies on strptime() to parse the user-specified
timestamp.


On current macOS, your examples work reasonably well in the following
variation:

$ FAKETIME_FMT="%Y-%m-%d %T %z" ./faketime -f '2018-06-26 09:00:03
+0200' gdate -R
Tue, 26 Jun 2018 09:00:03 +0200

$ FAKETIME_FMT="%Y-%m-%d %T %z" ./faketime -f '2018-06-26 09:00:03
+0300' gdate -R
Tue, 26 Jun 2018 08:00:03 +0200

$ FAKETIME_FMT="%Y-%m-%d %T %z" ./faketime -f '2018-06-26 09:00:03
+0400' gdate -R
Tue, 26 Jun 2018 07:00:03 +0200


Whereas on Debian, with the glibc implementation of strptime, we end up
with your results:

$ FAKETIME_FMT="%Y-%m-%d %T %z" ./faketime -f '2018-06-26 09:00:03
+0200' date -R
Tue, 26 Jun 2018 09:00:03 +0200

$ FAKETIME_FMT="%Y-%m-%d %T %z" ./faketime -f '2018-06-26 09:00:03
+0300' date -R
Tue, 26 Jun 2018 09:00:03 +0200

$ FAKETIME_FMT="%Y-%m-%d %T %z" ./faketime -f '2018-06-26 09:00:03
+0400' date -R
Tue, 26 Jun 2018 09:00:03 +0200


Apparently, glibc goes for a new tm->tm_gmtoff field and supports %z
(but not %Z) fully yet. This might give some headaches regarding
cross-platform compatibility, and implementing a completely own parser
(i.e., not using strptime()) does not seem viable, either. So yes, this
needs to be addressed, but will take some time.


As a workaround, you can throw anything at libfaketime what `date` can
interpret, as in

$ LD_PRELOAD=./libfaketime.so.1 FAKETIME_FMT=%s FAKETIME="`date +%s
-d'2018-06-26 09:00:03+0400'`" date -R
Tue, 26 Jun 2018 07:00:03 +0200


Best regards,
Wolfgang

#907264#15
Date:
2022-03-09 15:41:27 UTC
From:
To:
Control: reassign 907264 libc6 2.33-7
Control: retitle 907264 glibc's strptime does not handle %z and %Z as expected
Control: affects 907264 + faketime

Since the problem appears to be in strptime(), i'm reassigning this bug
to glibc.