考虑到我们距离 32 位 time_t 签名疯狂还不到 15 年,我决定开始尝试自己的东西,看看情况如何。我想看看什么会坏,什么会起作用。
我特别想知道的一件事是我的小系统是如何工作的。基本上我的 64 位 Linux 机器会很好,因为 time_t 已经更宽了,而且它不会在 2038 年爆炸。但这远不是故事的全部。 32 位机器仍然存在,并且比某些人想象的更普遍,这要归功于 Raspberry Pis 之类的东西的存在。
除非您特意安装 64 位风格的 Raspbian,否则您将获得 32 位系统。使用当前运行的 glibc 版本,您将碰壁。尝试起来很容易 – 您会注意到您实际上无法将时钟设置得那么远:
root@rpi4b:/tmp# date -s "2038-01-19 03:14:08 UTC" 日期:无效日期 '2038-01-19 03:14:08 UTC'
所以,好吧,戴上你的“作恶时间”帽子,提前一秒,等待好戏上演。再次从头开始,它是这样做的:
root@rpi4b:/tmp# systemctl 停止 chrony root@rpi4b:/tmp# date -s "2038-01-19 03:14:07 UTC" 太平洋标准时间 2038 年 1 月 18 日星期一 07:14:07 PM 根@rpi4b:/tmp# 来自 syslogd@rpi4b 的消息于 1 月 18 日 19:14:07 ... systemd[1]:运行主循环失败:参数无效
来自 systemd-journald@rpi4b 的广播消息(— XXXX-XX-XX XX:XX:XX):
systemd[1]:运行主循环失败:参数无效
来自 syslogd@rpi4b 的消息于 1 月 18 日 19:14:07 … systemd[1]:冻结执行。
来自 systemd-journald@rpi4b 的广播消息(— XXXX-XX-XX XX:XX:XX):
systemd[1]:冻结执行。
嘻嘻!看看那个吸盘烧伤。我特别喜欢 XX-XX 的东西。就像一个被淘汰的卡通人物。
现在,在你拿出干草叉之前,请记住 systemd 只是这里的信使。它只是在处理给定的内容。
另外,系统实际上还在这里。 systemd 基本上刚刚检查完毕,不会为您做更多的事情。它甚至不需要进行普通的“重启”,因为这实际上只是一个请求 init(pid 1,所以又是 systemd)来重启机器。你将需要使用“reboot -f”并忍受盒子上的东西可能发生的任何坏事。这就像拔掉插头,所以玩得开心。
发生了什么?如果你在遗迹中四处挖掘,你会发现 systemd 中的一个断言被触发了。它拒绝继续,除非 clock_gettime() 返回 0。显然,它返回了其他东西。 systemd 看到这个非零值并决定通过有效停止来保护自己。
所以你想“我知道,我会再试一次,这次 strace pid 1,看看实际上返回了什么”。在它嘎嘎作响之前你会得到这样的东西:
clock_gettime64(CLOCK_REALTIME, {tv_sec=2147483648, tv_nsec=898182}) = 0
… 什么?它返回0?是的……也不是。仔细看看。
clock_gettime 64返回 0。但是 systemd 调用了 clock_gettime。 strace 正在向您展示系统调用…但该系统调用是通过 C 库函数发生的,在本例中,该函数由 glibc 2.31 提供。如果你打开 glibc 的源代码并四处寻找 clock_gettime(),你会发现:
ret = __clock_gettime64 (clock_id, &tp64);
如果(ret == 0){ 如果(!in_time_t_range(tp64.tv_sec)){ __set_errno(EOVERFLOW);返回-1; }
首先调用(支持 64 位的)系统调用。然后假设成功(并且确实如此,每个 strace),然后查看它是否适合(32 位)time_t。它不会,因此将 errno 设置为 EOVERFLOW,并返回 -1。
这就是 systemd 得到的,所以它爆炸了。
glibc 说“我不能把这个放进那个,所以我没有通过这个电话”。
它包含在一堆预处理器 #if 测试中,因此它仅在 __TIMESIZE 未设置为 64 时运行,但你猜怎么着?在这个特殊的硬件和软件组合中,__TIMESIZE 实际上是 32。如果你愿意,可以在标题中四处转转,然后从这里开始跟随弹跳球:
./arm-linux-gnueabihf/bits/timesize.h:#define __TIMESIZE __WORDSIZE
…或者只是写一些愚蠢的东西给 printf(…, __TIMESIZE) 看看。
需要明确的是,这是 Pi 4B 上 Raspbian/Raspberry Pi OS 11(靶心)的 32 位版本上的 glibc 2.31。较新版本的操作系统几乎肯定不会以这种方式运行,因为 glibc 本身正在朝着即使在 32 位机器上也拥有 64 位时间的方向前进。一旦完成并汇总到一个版本中,期望它会消失。
…
是的,大约 10 年前,NetBSD 和 OpenBSD 撕掉了这个创可贴,现在它已经完成了。我知道。干杯。