[Bug] [libc] timer_gettime 拆秒前将总纳秒截断为 uint32_t,剩余时间查询错误
Maintainer thường phản hồi trong vòng 2 ngày
@Yunlk đang làm issue này rồi.
Từ ngày 24/10/2026.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 68/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- c
- Lĩnh vực
- backend, operating-systems
Hướng nghiên cứu
Đọc components/libc/compilers/common/ctime.c, đặc biệt là timer_gettime() quanh các dòng được báo cáo 1337–1375, và theo dõi cách số tick còn lại của bộ đếm được chuyển đổi sang nanô giây. Ví dụ số học độc lập cho thấy việc cắt cụt; hãy tái hiện ví dụ đó, sau đó xác minh kết quả với thời gian còn lại là 10 giây sau khi thay đổi. Giữ lại các kiểm tra tràn vòng của bộ đếm và phạm vi phép nhân trung gian, đồng thời xác nhận cấu hình bộ định thời POSIX bật đoạn mã này.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
RT-Thread Version
master, commit a59e72fb5c2f272761a2813fc9bd9fe18eb29d7d.
Affected area
libc / POSIX timers, components/libc/compilers/common/ctime.c, timer_gettime().
Hardware / Architecture / Toolchain
采用源码级算术隔离复现,不依赖特定开发板。该提交中的受影响实现由 RT_USING_POSIX_TIMER && RT_USING_CLOCK_TIME 启用。本报告尚未进行目标板复现。
问题描述 / Describe the bug
timer_gettime() 将总剩余纳秒存入 rt_uint32_t,之后才拆分秒和纳秒:
rt_uint32_t seconds, nanoseconds;
/* ... */
nanoseconds = ((remain_cnt - rt_clock_time_get_counter())
* rt_clock_time_get_res_scaled()) / RT_CLOCK_TIME_RESMUL;
seconds = nanoseconds / NANOSECOND_PER_SECOND;
nanoseconds = nanoseconds % NANOSECOND_PER_SECOND;
即使计数器表达式正确算出 10 秒,即 10,000,000,000 ns,赋给 32 位无符号变量时也会变成 1,410,065,408 ns。查询结果因此是 {tv_sec=1, tv_nsec=410065408},而不是 {10, 0}。
可运行的隔离复现 / Standalone arithmetic reproduction
下面明确模拟计数器换算已经正确得到总纳秒的情况,不调用宿主 libc 的 timer_gettime():
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
int main(void)
{
uint64_t converted_ns = UINT64_C(10000000000);
uint32_t seconds, nanoseconds;
nanoseconds = converted_ns;
seconds = nanoseconds / 1000000000;
nanoseconds %= 1000000000;
printf("%u.%09u\n", (unsigned)seconds, (unsigned)nanoseconds);
assert(seconds == 1 && nanoseconds == 410065408);
return 0;
}
输出:1.410065408;预期剩余时间为 10.000000000。
此前还在本地旧版同一函数的隔离计数器桩中复现过该结果;最新上游同样保留上述窄化顺序。完整目标端验证仍待进行。
Scope / Suggested direction
- 问题从总纳秒超过
UINT32_MAX(约 4.295 秒)起出现,不是几十年后的时间范围问题。 - 这是剩余时间查询结果错误,不表示定时器一定提前或延后触发。
- 后面的
(rt_int32_t)seconds不是这里的根因,数据在拆秒之前已经丢失。 - 建议总纳秒使用足够宽的类型,再拆分秒和纳秒;或在安全的单位下先拆秒、再换算余数。还应保留对计数器回绕及中间乘法范围的检查。
引入提交和版本 / Regression history
- 引入提交:0eb75ced70,2023-07-17,
[time]时钟框架重构 (#7794);首个包含该提交的正式 release 为 v5.0.2。 - 此前使用 64 位
remaining保存总纳秒,再分别赋值给秒和纳秒字段;该提交改为将总纳秒直接赋给 32 位nanoseconds,然后再拆秒。 rt_uint32_t seconds, nanoseconds的声明本身在更早实现中已经存在,但当时用于保存拆分后的字段,并非这次回归的来源。- 后续 743b614875 的时间子系统重构更换了计数接口名称,但保留了该窄化顺序。
其他实现参考 / Comparison
Linux 使用 64 位 ktime_t 转 timespec64;Zephyr 则先从剩余毫秒中拆秒,再将余数转换为纳秒。两种方式均避免这里的总纳秒 32 位中转。这不是对这些 OS 所有计时边界行为的保证。
- Ngôn ngữ chính
- C
- Star
- 12.3k
- Fork
- 5.5k
- Merge trung bình
- 7 ngày 8 giờ
- Pull request đã merge (30 ngày)
- 65
Chuẩn bị môi trường
Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của RT-Thread/rt-thread
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 67/100
RT-Thread/rt-thread#11951 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
RT-Thread/rt-thread#11949 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
[Bug] dfs_v2 tmpfs: ftruncate(fd, 0) frees the file buffer but reports success — use-after-free read/write and double free from a legal POSIX callCó thể đã có người làm @remukisama đã nhận 16 ngày trước. Đang mởin progress
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
RT-Thread/rt-thread#11902 · 4 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 2 ngày
-
[bsp][stm32][bluepill] README「快速上手」缺少重新生成 MDK 工程这一步,按文档操作无法编译通过Có thể làm lại được @moment-NEW đã nhận 33 ngày trước và không có pull request nào đang mở. Đang mởin progress
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
RT-Thread/rt-thread#11818 · 4 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 2 ngày
-
BSP BSP: Loongson bug RT-Smart
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
RT-Thread/rt-thread#11717 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
Tất cả issue của RT-Thread/rt-thread
Issue tương tự
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 83/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
containers/bubblewrap#826 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Vulkan: create_device reads the device extension list after freeing it (random crash at start)Đang mở
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 62/100
Revivedx/SavageWindRecomp#488 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
needs-device
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
-
feature/themes QA/No release-notes/exclude tests tests/missing-coverage tests/test-quality
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
brave/brave-browser#60971 ·
Maintainer thường phản hồi trong vòng 1 ngày