Skip to content

Commit d277d45

Browse files
committed
[libc] test: cover settimeofday() field validation
Requested in the review of #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 #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 #11922 Refs #11928
1 parent 3b45c07 commit d277d45

3 files changed

Lines changed: 116 additions & 0 deletions

File tree

‎components/libc/compilers/common/utest/Kconfig‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@ config RT_UTEST_LIBC_TIME
55
default n
66
depends on RT_USING_POSIX_CLOCK
77

8+
config RT_UTEST_LIBC_SETTIMEOFDAY
9+
bool "settimeofday() field validation Test"
10+
default n
11+
depends on RT_USING_RTC
12+
813
endmenu

‎components/libc/compilers/common/utest/SConscript‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ CPPPATH = [cwd]
88
if GetDepend(['RT_UTEST_LIBC_TIME']):
99
src += ['time_tc.c']
1010

11+
if GetDepend(['RT_UTEST_LIBC_SETTIMEOFDAY']):
12+
src += ['settimeofday_tc.c']
13+
1114
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
1215

1316
Return('group')
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright (c) 2006-2026, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* Test Case Name: settimeofday() field validation
9+
*
10+
* Test Objectives:
11+
* - Verify that timestamps above INT32_MAX are accepted on time64/long32 targets.
12+
* - Verify that a negative tv_usec is still rejected.
13+
* - Prevent regression of GitHub Issue #11922.
14+
*
15+
* Note: the rejections exercised here only happen when time_t is wider than long,
16+
* which is the time64/long32 configuration. On targets where the two are the same
17+
* width the old narrowing cast could not change the result, so the case would not
18+
* prove anything; it reports that and skips.
19+
*/
20+
21+
#include <rtthread.h>
22+
#include <rtdevice.h>
23+
#include <sys/time.h>
24+
#include <errno.h>
25+
#include "utest.h"
26+
27+
/* Run settimeofday() against the boundary values, then restore the clock. */
28+
static void settimeofday_time64_test(void)
29+
{
30+
struct timeval tv;
31+
struct timeval saved = { 0, 0 };
32+
rt_device_t rtc;
33+
int ret;
34+
35+
rtc = rt_device_find("rtc");
36+
if (rtc == RT_NULL)
37+
{
38+
LOG_I("no rtc device, skipping");
39+
return;
40+
}
41+
42+
if (sizeof(time_t) <= sizeof(long))
43+
{
44+
LOG_I("sizeof(time_t)=%d is not wider than sizeof(long)=%d, skipping",
45+
(int)sizeof(time_t), (int)sizeof(long));
46+
return;
47+
}
48+
49+
/* remember the current time so the rtc can be put back afterwards */
50+
if (gettimeofday(&saved, RT_NULL) != 0)
51+
{
52+
saved.tv_sec = 0;
53+
saved.tv_usec = 0;
54+
}
55+
56+
/* INT32_MAX + 1: the first value the old (long) cast turned negative */
57+
tv.tv_sec = (time_t)2147483647 + 1;
58+
tv.tv_usec = 0;
59+
LOG_I("tv_sec = INT32_MAX + 1");
60+
uassert_int_equal(settimeofday(&tv, RT_NULL), 0);
61+
62+
/* 2040-01-01, the value reported in #11922 */
63+
tv.tv_sec = (time_t)2208988800;
64+
tv.tv_usec = 0;
65+
LOG_I("tv_sec = 2208988800 (2040-01-01)");
66+
uassert_int_equal(settimeofday(&tv, RT_NULL), 0);
67+
68+
/* 2106-02-07, UINT32_MAX */
69+
tv.tv_sec = (time_t)4294967295U;
70+
tv.tv_usec = 0;
71+
LOG_I("tv_sec = 4294967295 (2106-02-07)");
72+
uassert_int_equal(settimeofday(&tv, RT_NULL), 0);
73+
74+
/* a negative tv_usec is still invalid and must keep being rejected */
75+
tv.tv_sec = (time_t)1000000000;
76+
tv.tv_usec = -1;
77+
LOG_I("tv_usec = -1 must be rejected");
78+
errno = 0;
79+
ret = settimeofday(&tv, RT_NULL);
80+
uassert_int_equal(ret, -1);
81+
uassert_int_equal(errno, EINVAL);
82+
83+
/* put the clock back */
84+
if (settimeofday(&saved, RT_NULL) != 0)
85+
{
86+
LOG_W("failed to restore the rtc");
87+
}
88+
}
89+
90+
/* Initialize the settimeofday test. */
91+
static rt_err_t utest_tc_init(void)
92+
{
93+
return RT_EOK;
94+
}
95+
96+
/* Clean up the settimeofday test. */
97+
static rt_err_t utest_tc_cleanup(void)
98+
{
99+
return RT_EOK;
100+
}
101+
102+
/* Run the settimeofday test case. */
103+
static void testcase(void)
104+
{
105+
UTEST_UNIT_RUN(settimeofday_time64_test);
106+
}
107+
108+
UTEST_TC_EXPORT(testcase, "components.libc.settimeofday", utest_tc_init, utest_tc_cleanup, 10);

0 commit comments

Comments
 (0)