Bug 18732 - 将硬件时钟设置为 '2038-01-19 03:14:08 UTC', 报错: hwclock: settimeofday() 失败: 无效的参数.
Summary: 将硬件时钟设置为 '2038-01-19 03:14:08 UTC', 报错: hwclock: settimeofday() 失败: 无效的参数.
Status: NEW
Alias: None
Product: ANCK 5.10 Dev
Classification: ANCK
Component: general/others (show other bugs) general/others
Version: unspecified
Hardware: x86_64 Linux
: P3-Medium S3-normal
Target Milestone: ---
Assignee: geliwei-ali
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2025-02-11 14:54 UTC by songcy2025
Modified: 2025-04-16 17:39 UTC (History)
3 users (show)

See Also:


Attachments
去掉 (int) 强转, 问题不复现了, (40 bytes, text/plain)
2025-02-14 12:27 UTC, songcy2025
Details
去掉 (int) 强转, 问题不复现了 (191.91 KB, image/png)
2025-02-14 12:46 UTC, songcy2025
Details

Note You need to log in before you can comment on or make changes to this bug.
Description songcy2025 2025-02-11 14:54:02 UTC
Description of problem:
将硬件时钟设置为 '2038-01-19 03:14:08 UTC', 报错: hwclock: settimeofday() 失败: 无效的参数.

Version-Release number of selected component (if applicable):
Anolis OS release 8.9

How reproducible:
在默认的系统环境下.


Steps to Reproduce:
1.进入系统, 在终端依次执行下面的命令:
/usr/bin/timedatectl set-timezone Asia/Shanghai
sudo /usr/sbin/hwclock --set --date '2038-01-19 03:14:08 UTC'
sudo /usr/sbin/hwclock --hctosys

2.观察终端执行指令后的回显日志,
[songcy@anolis ~]$ sudo /usr/sbin/hwclock --hctosys
hwclock: settimeofday() 失败: 无效的参数
[songcy@anolis ~]$
[songcy@anolis ~]$ date
2025年 02月 11日 星期二 14:47:18 CST
[songcy@anolis ~]$

Actual results:
设置系统时钟失败, date 回显时间不符合设置的预期.

Expected results:
1.通过 系统工具 hwclock 设置系统时钟为 '2038-01-19 03:14:08 UTC'不报错,
2.执行指令 'date' 回显时间 符合设置的时间预期

Additional info: 无
Comment 1 songcy2025 2025-02-11 15:07:53 UTC
补充一下信息,
[songcy@anolis ~]$ sudo /usr/sbin/hwclock --set --date '2037-01-19 03:14:08 UTC'
[songcy@anolis ~]$ sudo /usr/sbin/hwclock --hctosys
[songcy@anolis ~]$ date
2037年 01月 19日 星期一 11:14:14 CST
[songcy@anolis ~]$ 
[songcy@anolis ~]$ sudo /usr/sbin/hwclock --set --date '2038-01-19 03:14:08 UTC'
[songcy@anolis ~]$ sudo /usr/sbin/hwclock --hctosys
hwclock: settimeofday() 失败: 无效的参数
[songcy@anolis ~]$

注意:
设置 系统时间为 '2037-01-19 03:14:08 UTC', 没有执行报错,

下面是问题相关的参考链接:
[1] https://askubuntu.com/questions/299475/will-the-linux-clock-fail-at-january-19-2038-31408
[2] http://painterengineering.com/pei_unixtime.pdf
[3] https://www.zhihu.com/question/432241505
Comment 2 xunlei alibaba_cloud_group 2025-02-12 11:13:53 UTC
1)设置为 2037 年时,成功。
# /usr/sbin/hwclock --set --date '2037-01-19 03:14:08 UTC'
# /usr/sbin/hwclock --hctosys

# bpftrace settimeofday.bt 
Attaching 2 probes...
do_sys_settimeofday64 comm:hwclock, timespec64: sec=0x0 nsec=0x0, timezone: tz_minuteswest=0 tz_dsttime=0
do_sys_settimeofday64 retval is=0
do_sys_settimeofday64 comm:hwclock, timespec64: sec=0x0 nsec=0x0, timezone: tz_minuteswest=-480 tz_dsttime=0
do_sys_settimeofday64 retval is=0
do_sys_settimeofday64 comm:hwclock, timespec64: sec=0x7e1ecc86 nsec=0x0, timezone: tz_minuteswest=0 tz_dsttime=0
do_sys_settimeofday64 retval is=0

syscall调用栈信息:
@[
    do_sys_settimeofday64+1
    __x64_sys_clock_settime+104
    do_syscall_64+49
    entry_SYSCALL_64_after_hwframe+98
]: 1
@[
    do_sys_settimeofday64+1
    __x64_sys_settimeofday+129
    do_syscall_64+49
    entry_SYSCALL_64_after_hwframe+98
]: 2

2)设置为 2038年时,失败。
发现 hwclock 没有下发第3次 syscall clock_settime(CLOCK_REALTIME, ...);

# /usr/sbin/hwclock --set --date '2038-01-19 03:14:08 UTC'
# /usr/sbin/hwclock --hctosys
hwclock: settimeofday() 失败: 无效的参数

# bpftrace settimeofday.bt 
Attaching 2 probes...
do_sys_settimeofday64 comm:hwclock, timespec64: sec=0x0 nsec=0x0, timezone: tz_minuteswest=0 tz_dsttime=0
do_sys_settimeofday64 retval is=0
do_sys_settimeofday64 comm:hwclock, timespec64: sec=0x0 nsec=0x0, timezone: tz_minuteswest=-480 tz_dsttime=0
do_sys_settimeofday64 retval is=0

syscall调用栈信息:
@[
    do_sys_settimeofday64+1
    __x64_sys_settimeofday+129
    do_syscall_64+49
    entry_SYSCALL_64_after_hwframe+98
]: 2


因此,不是内核的问题,是hwclock程序的实现逻辑哪里有问题,内核已经可以正确处理year-2038问题(例如执行date -s '2038-01-19 03:14:08 UTC' 可以成功),看起来是hwclock工具没有解决 y2038 问题。
Comment 3 xunlei alibaba_cloud_group 2025-02-12 11:28:50 UTC
From chatgpt:hwclock 哪个版本解决了 2038 问题?
2038 问题是指在使用 32 位时间戳的系统中,时间表示的最大值为 2038 年 1 月 19 日 03:14:07 UTC。超过这个时间点后,时间戳会溢出并导致系统错误。为了解决这个问题,需要使用 64 位时间戳。

hwclock 是一个用于读取和设置硬件时钟(RTC)的工具。为了支持 64 位时间戳并解决 2038 问题,hwclock 需要进行相应的更新。以下是一些相关信息:

hwclock 的版本历史
hwclock 从 util-linux 2.32 版本开始:
util-linux 2.32 及更高版本中的 hwclock 工具引入了对 64 位时间戳的支持,从而解决了 2038 问题。
在这些版本中,hwclock 使用 64 位时间戳来处理时间和日期,确保在 2038 年之后的时间也能正确处理。
检查 util-linux 版本
你可以通过以下命令检查当前系统上安装的 util-linux 版本:
util-linux --version
Comment 4 xunlei alibaba_cloud_group 2025-02-12 11:30:43 UTC
(In reply to xunlei from comment #3)
> From chatgpt:hwclock 哪个版本解决了 2038 问题?
> 2038 问题是指在使用 32 位时间戳的系统中,时间表示的最大值为 2038 年 1 月 19 日 03:14:07
> UTC。超过这个时间点后,时间戳会溢出并导致系统错误。为了解决这个问题,需要使用 64 位时间戳。
> 
> hwclock 是一个用于读取和设置硬件时钟(RTC)的工具。为了支持 64 位时间戳并解决 2038 问题,hwclock
> 需要进行相应的更新。以下是一些相关信息:
> 
> hwclock 的版本历史
> hwclock 从 util-linux 2.32 版本开始:
> util-linux 2.32 及更高版本中的 hwclock 工具引入了对 64 位时间戳的支持,从而解决了 2038 问题。
> 在这些版本中,hwclock 使用 64 位时间戳来处理时间和日期,确保在 2038 年之后的时间也能正确处理。
> 检查 util-linux 版本
> 你可以通过以下命令检查当前系统上安装的 util-linux 版本:
> util-linux --version

rpm -q util-linux
Comment 5 songcy2025 2025-02-13 09:51:38 UTC
(In reply to xunlei from comment #4)

提单的问题场景 环境是 util-linux-2.32.1-43.0.1.an8.x86_64,
[songcy@anolis ~]$ rpm -qf $(which hwclock)
util-linux-2.32.1-43.0.1.an8.x86_64
[songcy@anolis ~]$ rpm -q util-linux
util-linux-2.32.1-43.0.1.an8.x86_64
[songcy@anolis ~]$ 

继续更新工具 util-linux 到最新版本, 问题复现,
[songcy@anolis ~]$ yum --showduplicates list util-linux
AnolisOS-8 - Extras                                                                                 9.5 kB/s | 2.3 kB     00:00    
Extra Packages for Enterprise Linux Modular 8 - x86_64                                              6.7 kB/s | 733 kB     01:49    
已安装的软件包
util-linux.x86_64                                           2.32.1-43.0.1.an8                                              @anaconda
可安装的软件包
util-linux.x86_64                                           2.32.1-43.0.1.an8                                              BaseOS   
util-linux.x86_64                                           2.32.1-44.0.1.an8.1                                            BaseOS   
util-linux.x86_64                                           2.32.1-45.0.1.an8.1                                            BaseOS   
util-linux.x86_64                                           2.32.1-46.0.1.an8                                              BaseOS   
util-linux.x86_64                                           2.32.1-46.0.3.an8                                              BaseOS   
[songcy@anolis ~]$
[songcy@anolis ~]$ sudo yum install util-linux-2.32.1-46.0.3.an8
...
已升级:
  libblkid-2.32.1-46.0.3.an8.x86_64              libfdisk-2.32.1-46.0.3.an8.x86_64       libmount-2.32.1-46.0.3.an8.x86_64        
  libsmartcols-2.32.1-46.0.3.an8.x86_64          libuuid-2.32.1-46.0.3.an8.x86_64        util-linux-2.32.1-46.0.3.an8.x86_64      
  util-linux-user-2.32.1-46.0.3.an8.x86_64      

完毕!
[songcy@anolis ~]$ 
[songcy@anolis ~]$ rpm -qf $(which hwclock)
util-linux-2.32.1-46.0.3.an8.x86_64
[songcy@anolis ~]$ rpm -q util-linux
util-linux-2.32.1-46.0.3.an8.x86_64
[songcy@anolis ~]$
hwclock,来自 util-linux 2.32.1
[songcy@anolis ~]$ 
[songcy@anolis ~]$ sudo /usr/sbin/hwclock --set --date '2038-01-19 03:14:08 UTC'
[songcy@anolis ~]$ sudo /usr/sbin/hwclock --hctosys
hwclock: settimeofday() 失败: 无效的参数
[songcy@anolis ~]$
Comment 6 songcy2025 2025-02-14 12:27:36 UTC
Created attachment 1298 [details]
去掉 (int) 强转, 问题不复现了,
Comment 7 songcy2025 2025-02-14 12:40:53 UTC
Dear xunlei,

我们在 gdb 调试 hwclock 的时候, 找到了问题点, 通过修改源码后重编译, "2038 年" 的问题得到了解决, 报错的问题不再复现.

具体修改内容如下:
static struct timeval time_inc(struct timeval addend, double increment)
{
	struct timeval newtime;

	// newtime.tv_sec = addend.tv_sec + (int)increment;
	newtime.tv_sec = addend.tv_sec + increment;
	// newtime.tv_usec = addend.tv_usec + (increment - (int)increment) * 1E6;
	newtime.tv_usec = addend.tv_usec + (increment - increment) * 1E6;

修改后重新编译 hwclock, 执行指令的现象如下:
[songcy@anolis util-linux-2.32.1]$ sudo ./hwclock --set --date '2038-01-19 03:14:08 UTC'
[sudo] songcy 的密码:
[songcy@anolis util-linux-2.32.1]$ 
[songcy@anolis util-linux-2.32.1]$ sudo ./hwclock --hctosys
[songcy@anolis util-linux-2.32.1]$ date
2038年 01月 19日 星期二 11:14:16 CST
[songcy@anolis util-linux-2.32.1]$
注: 从结果来看, "2038 问题" 的报错 没有复现了,

下面是我的定位问题的具体步骤, 可以按需参考一下,
1. 首先需要获取到 当前版本工具的源码, 重新编译出可供调试的二进制程序,

  837  rpm -qf $(which hwclock) # 查询当前系统中工具的版本号
  838  yum --showduplicates list util-linux # 查询当前支持的版本号, 需要下载当前版本匹配的源码包
  843  yumdownloader --source util-linux-2.32.1-46.0.3.an8.x86_64 # 下载源码包
  844  ls -lrt 
  845  mkdir util-linux-2.32.1-46.0.3.an8.src
  846  cp util-linux-2.32.1-46.0.3.an8.src.rpm util-linux-2.32.1-46.0.3.an8.src
  847  cd util-linux-2.32.1-46.0.3.an8.src
  849  rpm2cpio util-linux-2.32.1-46.0.3.an8.src.rpm | cpio -idv # 解压 rpm 包
  850  ls -lrt | grep -v ".patch"
  851  tar -xf util-linux-2.32.1.tar.xz
  852  ls -lrt | grep -v ".patch"
  853  cd util-linux-2.32.1/
  854  ./configure --disable-all-programs --enable-hwclock --enable-debug # 只编译 hwclock,避免编译整个 util-linux
  858  grep "^CFLAGS \= " Makefile 
  859  vim Makefile
        ==> 修改一下 CFLAGS = -g3 -O0 # 禁用优化 并 启用完整的调试信息
  861  make -j$(nproc)
  862  ls -lrt 
  863  sudo gdb ./hwclock

2.然后 gdb 调试 hwclock

(gdb) run --set --date '2038-01-19 03:14:08 UTC'
Starting program: /home/songcy/proj_repositories/util-linux-2.32.1-43.0.1.an8.src/util-linux-2.32.1/tmp/util-linux-2.32.1-46.0.3.an8.src/util-linux-2.32.1/hwclock --set --date '2038-01-19 03:14:08 UTC'
[Inferior 1 (process 309703) exited normally]
(gdb) source /home/songcy/proj_repositories/my-work-place/hwclock_gdb_breakpoints.txt 
Breakpoint 1 at 0x402ad1: file sys-utils/hwclock.c, line 370.
Breakpoint 2 at 0x404354: file sys-utils/hwclock.c, line 1103.
Breakpoint 3 at 0x403ac0: file sys-utils/hwclock.c, line 907.
Breakpoint 4 at 0x4053eb: file sys-utils/hwclock-rtc.c, line 158.
Breakpoint 5 at 0x40297d: file sys-utils/hwclock.c, line 328.
Breakpoint 6 at 0x7ffff74eba70
Breakpoint 7 at 0x403dc0: file sys-utils/hwclock.c, line 981.
Breakpoint 8 at 0x40311b: file sys-utils/hwclock.c, line 617.
(gdb) info breakpoints 
Num     Type           Disp Enb Address            What
1       breakpoint     keep n   0x0000000000402ad1 in read_hardware_clock 
                                                   at sys-utils/hwclock.c:370
2       breakpoint     keep n   0x0000000000404354 in main at sys-utils/hwclock.c:1103
3       breakpoint     keep n   0x0000000000403ac0 in manipulate_clock 
                                                   at sys-utils/hwclock.c:907
4       breakpoint     keep n   0x00000000004053eb in do_rtc_read_ioctl 
                                                   at sys-utils/hwclock-rtc.c:158
5       breakpoint     keep n   0x000000000040297d in mktime_tz at sys-utils/hwclock.c:328
6       breakpoint     keep n   0x00007ffff74eba70 <timegm>
7       breakpoint     keep y   0x0000000000403dc0 in manipulate_clock 
                                                   at sys-utils/hwclock.c:981
8       breakpoint     keep y   0x000000000040311b in set_system_clock 
                                                   at sys-utils/hwclock.c:617
(gdb) run --hctosys
Starting program: /home/songcy/proj_repositories/util-linux-2.32.1-43.0.1.an8.src/util-linux-2.32.1/tmp/util-linux-2.32.1-46.0.3.an8.src/util-linux-2.32.1/hwclock --hctosys

Breakpoint 7, manipulate_clock (ctl=0x7fffffffe250, set_time=0, startup_time=..., 
    adjtime=0x7fffffffe210) at sys-utils/hwclock.c:981
981                     if (!ctl->show)
(gdb) bt
#0  manipulate_clock (ctl=0x7fffffffe250, set_time=0, startup_time=..., 
    adjtime=0x7fffffffe210) at sys-utils/hwclock.c:981
#1  0x0000000000404957 in main (argc=0, argv=0x7fffffffe368) at sys-utils/hwclock.c:1363
(gdb) list 
976                      */
977                     calculate_adjustment(ctl, adjtime->drift_factor,
978                                          adjtime->last_adj_time,
979                                          adjtime->not_adjusted,
980                                          hclocktime.tv_sec, &tdrift);
981                     if (!ctl->show)
982                             hclocktime = time_inc(tdrift, hclocktime.tv_sec);
983
984                     startup_hclocktime =
985                      time_inc(hclocktime, time_diff(startup_time, read_time));
(gdb) 

注意: 上面是我调试使用到的断点, 重点关注 断点 7 和 8, 这两个点 会定位到问题,
问题现象是 hclocktime.tv_sec 转变成了 负数, hclocktime.tv_usec 值不为 0,

下一步:
请 check 一下 方法 time_inc 的代码修改, 我对源码的设计原理不理解, 这么粗暴的修改预期会存在问题.
Comment 8 songcy2025 2025-02-14 12:46:05 UTC
Created attachment 1299 [details]
去掉 (int) 强转, 问题不复现了
Comment 9 songcy2025 2025-02-14 12:58:21 UTC
(In reply to xunlei from comment #2)

Dear Xunlei,

按照你前面所述, 当前这个问题 最直接的表现是 hwclock 用户态工具的代码逻辑问题, 
这个问题 应该找哪位 ower 来支撑? 或者帮忙内部交接一下呢?
Comment 10 Weisson alibaba_cloud_group 2025-02-20 15:59:05 UTC
https://github.com/util-linux/util-linux/pull/1294
上游的讨论。
Comment 11 Weisson alibaba_cloud_group 2025-02-20 17:30:26 UTC
构建完成,待发布 http://build.openanolis.cn/buildinfo?buildID=38895
Comment 12 songcy2025 2025-02-20 18:12:35 UTC
(In reply to Weisson from comment #11)
> 构建完成,待发布 http://build.openanolis.cn/buildinfo?buildID=38895

Dear Weisson,

我正在关注 如何应用当前问题的解决方案 到我们的项目上.

1. 关于应用你的修复方案, 首先我能想到的是 直接 install 修复问题后的 rpm 包, 
我没有看到 "2.23.1-46.0.4" 版本的发布, 我在哪里可以找到这个版本?

[songcy@anolis proj_repositories]$ rpm -qf $(which hwclock)
util-linux-2.32.1-46.0.3.an8.x86_64
[songcy@anolis proj_repositories]$ yum --showduplicates list util-linux
... 
已安装的软件包
util-linux.x86_64   2.32.1-46.0.3.an8   @BaseOS
可安装的软件包     
util-linux.x86_64   2.32.1-43.0.1.an8   BaseOS 
util-linux.x86_64   2.32.1-44.0.1.an8.1 BaseOS 
util-linux.x86_64   2.32.1-45.0.1.an8.1 BaseOS 
util-linux.x86_64   2.32.1-46.0.1.an8   BaseOS 
util-linux.x86_64   2.32.1-46.0.3.an8   BaseOS 
[songcy@anolis proj_repositories]$

Changelog	* Thu Feb 20 2025 Weisson <Weisson@linux.alibaba.com> 2.23.1-46.0.4
- bugfix:  anbz 18732.
- from upstream: https://github.com/util-linux/util-linux/pull/1294.

2. 其次 我考虑拉取 工具的最新代码 编译 RPM, 并替换到我们产品的根文件系统,
包含修复提交的 util-linux 源码, 我在哪能够获取, 地址能发一下不?

期待你的回复.
Comment 13 Weisson alibaba_cloud_group 2025-03-31 15:45:03 UTC
https://gitee.com/src-anolis-os/util-linux/tree/a8/(In reply to songcy2025 from comment #12)
> (In reply to Weisson from comment #11)
> > 构建完成,待发布 http://build.openanolis.cn/buildinfo?buildID=38895
> 
> Dear Weisson,
> 
> 我正在关注 如何应用当前问题的解决方案 到我们的项目上.
> 
> 1. 关于应用你的修复方案, 首先我能想到的是 直接 install 修复问题后的 rpm 包, 
> 我没有看到 "2.23.1-46.0.4" 版本的发布, 我在哪里可以找到这个版本?
> 
> [songcy@anolis proj_repositories]$ rpm -qf $(which hwclock)
> util-linux-2.32.1-46.0.3.an8.x86_64
> [songcy@anolis proj_repositories]$ yum --showduplicates list util-linux
> ... 
> 已安装的软件包
> util-linux.x86_64   2.32.1-46.0.3.an8   @BaseOS
> 可安装的软件包     
> util-linux.x86_64   2.32.1-43.0.1.an8   BaseOS 
> util-linux.x86_64   2.32.1-44.0.1.an8.1 BaseOS 
> util-linux.x86_64   2.32.1-45.0.1.an8.1 BaseOS 
> util-linux.x86_64   2.32.1-46.0.1.an8   BaseOS 
> util-linux.x86_64   2.32.1-46.0.3.an8   BaseOS 
> [songcy@anolis proj_repositories]$
> 
> Changelog	* Thu Feb 20 2025 Weisson <Weisson@linux.alibaba.com> 2.23.1-46.0.4
> - bugfix:  anbz 18732.
> - from upstream: https://github.com/util-linux/util-linux/pull/1294.
> 
> 2. 其次 我考虑拉取 工具的最新代码 编译 RPM, 并替换到我们产品的根文件系统,
> 包含修复提交的 util-linux 源码, 我在哪能够获取, 地址能发一下不?
> 
> 期待你的回复.

项目地址在这里:
https://gitee.com/src-anolis-os/util-linux/tree/a8/
Comment 14 songcy2025 2025-04-16 17:39:35 UTC
(In reply to Weisson from comment #13)

收到,
谢谢 Weisson