调用clock_gettime的代码今日突然失效,可能是什么原因?
核心故障原因
99%概率是32位有符号整数溢出,和代码运行时长直接相关,完全符合「之前一直正常、某天突然失效」的特征:
int32_t能存储的最大正整数为2147483647,这里把单调时钟的时间转成毫秒单位存在32位整型里,系统累计开机运行约24.8天之后,tp.tv_sec * 1000的计算结果就会超过int32_t的数值上限,直接溢出为负数。- 溢出后
tnow变为负数值,tnow - decoder->last_dumped的计算结果会完全错乱:要么结果为负永远达不到>=300的触发条件,分支逻辑完全不执行;要么数值无规律跳变导致业务逻辑异常。 - 之前代码能正常运行,只是因为服务启动/设备重启后,系统运行时长远没到24.8天的溢出阈值,数值一直处于合法范围,跑到故障当天刚好跨过溢出临界点。
剩余小概率故障点:
- 最近修改过
decoder结构体定义,增删字段导致last_dumped的内存偏移错误,读写到了错误的内存位置 - 编译选项变更导致
struct timespec结构体对齐异常,clock_gettime写入的时间值读取错误 - 系统内核升级后
CLOCK_MONOTONIC的行为异常(这类情况极其罕见)
修复方案
- 将毫秒时间戳的存储类型从32位整型替换为64位整型,从根源避免溢出,注意计算时先做类型强转,防止乘法运算阶段就触发溢出:
struct timespec tp; clock_gettime(CLOCK_MONOTONIC, &tp); // 先把tv_sec强转为int64_t再做乘法,避免32位运算阶段溢出 int64_t tnow = (int64_t)tp.tv_sec * 1000 + tp.tv_nsec / 1000000; if (tnow - decoder->last_dumped >= 300) { decoder->last_dumped = tnow; // 原有业务逻辑 }
- 同步把
decoder结构体里last_dumped字段的类型也改为int64_t,不要残留32位类型定义。 - 如果改完64位类型仍有问题,再排查结构体对齐、编译选项、内核变更类小概率问题。
内容的提问来源于stack exchange,提问作者YOU
相关产品推荐
相关产品推荐

