Repository navigation
Conversation
settimeofday() decided whether the caller's arguments were valid by casting
them to long first:
if (tv != RT_NULL && (long)tv->tv_usec >= 0 && (long)tv->tv_sec >= 0)
On ILP32 targets where time_t is 64 bit (time64/long32, e.g. 32-bit ARM with
the default RT-Thread libc configuration) that cast narrows tv_sec to 32 bits.
Every timestamp from INT32_MAX + 1 to UINT32_MAX becomes negative, so the
function rejects perfectly valid values with EINVAL before it ever reaches the
RTC device. 2208988800 (2040-01-01) is rejected this way.
Validate the fields by their own type instead; tv_sec is compared as time_t,
which is signed in every configuration RT-Thread ships.
Verified on bsp/qemu-vexpress-a9 (32-bit ARM, RT_USING_RTC, on-board rtc
device, arm-none-eabi-gcc 15.2.1, QEMU 11.0.0), where the probe reports
sizeof(time_t) = 8 and sizeof(long) = 4:
tv_sec before after
0 ret=0 ret=0
2147483647 ret=0 ret=0
2147483648 ret=-1, errno=EINVAL ret=0
2208988800 ret=-1, errno=EINVAL ret=0
4294967295 ret=-1, errno=EINVAL ret=0
Values at or below INT32_MAX behave exactly as before.
Note: tv_usec is only checked for a negative value here, POSIX also requires
it to be below 1000000. That is a separate gap and is left untouched.
Refs RT-Thread#11922
|
👋 感谢您对 RT-Thread 的贡献!Thank you for your contribution to RT-Thread! 为确保代码符合 RT-Thread 的编码规范,请在你的仓库中执行以下步骤运行代码格式化工作流(如果格式化CI运行失败)。 🛠 操作步骤 | Steps
完成后,提交将自动更新至 如有问题欢迎联系我们,再次感谢您的贡献!💐 |
📌 Code Review Assignment🏷️ Tag: componentsReviewers: @Maihuanyi Changed Files (Click to expand)
🏷️ Tag: components_libcReviewers: @GorrayLi @mysterywolf Changed Files (Click to expand)
📊 Current Review Status (Last Updated: 2026-10-28 13:53 CST)
📝 Review Instructions
|
|
|
如果可以请增加utest的测试用例 |
Requested in the review of RT-Thread#11928: add a utest for the narrowing fix. The case walks the values whose byte range collides with INT32_MAX, so it only proves something on targets where time_t is wider than long. Instead of silently passing elsewhere it reports the sizes and skips: sizeof(time_t)=8 is not wider than sizeof(long)=4, skipping Cases, all against the on-board rtc device: tv_sec = 2147483648 INT32_MAX + 1, first value the old cast broke tv_sec = 2208988800 2040-01-01, the value from RT-Thread#11922 tv_sec = 4294967295 2106-02-07 tv_usec = -1 must keep being rejected with EINVAL The clock is saved before the first write and restored afterwards. Without the fix in the previous commit the three large timestamps fail, while the negative tv_usec case still passes: [E/utest] tv_sec = INT32_MAX + 1 ((settimeofday(&tv, 0)) not == (0)) [E/utest] tv_sec = 2208988800 ... ((settimeofday(&tv, 0)) not == (0)) [E/utest] tv_sec = 4294967295 ... ((settimeofday(&tv, 0)) not == (0)) [I/utest] tv_usec = -1 must be rejected [E/utest] [ FAILED ] components.libc.settimeofday Verified on bsp/qemu-vexpress-a9 (RT_USING_RTC, on-board rtc device): with the fix : PASSED without the fix : FAILED, the three boundary assertions listed above Registered under its own Kconfig symbol rather than the existing time_tc.c, since it depends on RT_USING_RTC while that case depends on RT_USING_POSIX_CLOCK. Refs RT-Thread#11922 Refs RT-Thread#11928
|
utest 已补上,提交 用例内容新增 没有塞进已有的 覆盖四个点:
两个细节:
验证:用例有鉴别力带修复( 不带修复(仅把 三条边界断言全失败,而 提交前我又在 clang-format 提交之上重编重跑了一次,仍然 PASSED,确认格式化没有动到修复逻辑( 一个提醒PR 当前 diff 是
|
拉取/合并请求描述:(PR description)
[
为什么提交这份PR (why to submit this PR)
修复 #11922。
settimeofday()用强转后的值判断参数是否合法:在 ILP32 且
time_t为 64 位的目标上(time64/long32,例如 32 位 ARM + RT-Thread 默认 libc 配置),这个(long)会把tv_sec截成 32 位。于是INT32_MAX + 1到UINT32_MAX区间的每个合法时间戳都变成负数,函数在碰到 RTC 设备之前就以EINVAL拒绝。2208988800(2040-01-01)就是这样被拒的。你的解决方案是什么 (what is your solution)
按字段自身类型校验,不做强转:
tv_sec直接按time_t比较,RT-Thread 各配置下time_t都是有符号类型,所以>= 0的判断依然有效,只是不再窄化。tv_usec的强转也一并去掉,只是为了两处写法统一;它在 ILP32 上原本就没问题(suseconds_t32 位)。如果希望改动更小,只动tv_sec也可以。请提供验证的bsp和config (provide the config and bsp)
bsp/qemu-vexpress-a9(32 位 ARM,RT_USING_RTC=y,板上有rtc设备)1c801efa运行时探针确认
sizeof(time_t)=8、sizeof(long)=4,正是 time64/long32。逐点扫描边界,同一份固件改前/改后各跑一次:
首个被拒值正好是
INT32_MAX + 1,与 issue 描述的区间一致;INT32_MAX及以下行为完全未变。两点说明
未包含的相邻缺陷:当前只校验
tv_usec >= 0,POSIX 还要求< 1000000。传tv_usec = 5000000会被放行并送进 RTC 驱动。这属于另一处校验缺失,为了避免把两种行为变更混在一个补丁里,本次没有改动,是否收紧由维护者判断。关于 utest:这个用例要能跑,前提是系统里有
rtc设备(_control_rtc()通过rt_device_find("rtc")查找,找不到会返回-RT_ENOSYS,这与强转问题是两条不同的失败路径)。CI 里的 qemu-vexpress-a9 有 rtc,但其他跑 utest 的 BSP 未必有,直接加会因找不到设备而误失败。如果维护者确认放在哪个 BSP/config 合适,我可以补一条RT_USING_RTC条件下编译的用例,断言INT32_MAX + 1与2208988800能通过。]
当前拉取/合并请求的状态 Intent for your PR
必须选择一项 Choose one (Mandatory):
代码质量 Code Quality:
我在这个拉取/合并请求中已经考虑了 As part of this pull request, I've considered the following:
#if 0代码,不包含已经被注释了的代码 All redundant code is removed and cleaned up