Skip to content

Commit ce1947a

Browse files
committed
Add clock_gettime model
Add a library model for `clock_gettime`: - Model follows POSIX specification with proper error handling - Non-deterministic behavior covers both success and failure paths - Validates timespec structure with appropriate constraints - Sets errno correctly (EFAULT for null pointer, EINVAL on failure) Fixes: #7639
1 parent 56d8598 commit ce1947a

File tree

3 files changed

+128
-0
lines changed

3 files changed

+128
-0
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#include <assert.h>
2+
#include <stdint.h>
3+
#include <time.h>
4+
5+
// Test function from the issue description
6+
uint32_t my_time(void)
7+
{
8+
struct timespec t;
9+
int ret = clock_gettime(CLOCK_MONOTONIC, &t);
10+
11+
// If clock_gettime fails, return a safe value
12+
if(ret != 0)
13+
{
14+
return 0;
15+
}
16+
17+
return (t.tv_nsec / 1000000) + ((t.tv_sec % 86400) * 1000);
18+
}
19+
20+
int main()
21+
{
22+
// Test null pointer behavior
23+
int result_null = clock_gettime(CLOCK_REALTIME, 0);
24+
if(result_null == -1)
25+
{
26+
// errno should be set to EFAULT for null pointer
27+
assert(errno == EFAULT);
28+
}
29+
30+
struct timespec ts;
31+
32+
// Test basic functionality with different clock types
33+
int result1 = clock_gettime(CLOCK_REALTIME, &ts);
34+
assert(result1 == 0 || result1 == -1);
35+
36+
if(result1 == 0)
37+
{
38+
// If successful, tv_nsec should be in valid range
39+
assert(ts.tv_nsec >= 0 && ts.tv_nsec <= 999999999L);
40+
}
41+
42+
// Test with CLOCK_MONOTONIC
43+
int result2 = clock_gettime(CLOCK_MONOTONIC, &ts);
44+
assert(result2 == 0 || result2 == -1);
45+
46+
if(result2 == 0)
47+
{
48+
// If successful, tv_nsec should be in valid range
49+
assert(ts.tv_nsec >= 0 && ts.tv_nsec <= 999999999L);
50+
}
51+
52+
// Test the my_time function from the issue
53+
// Note: my_time() handles the failure case internally
54+
uint32_t time_result = my_time();
55+
// Should return either 0 (on failure) or valid millisecond value within a day
56+
assert(time_result < 86400000 || time_result == 0);
57+
58+
return 0;
59+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--pointer-check --bounds-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

src/ansi-c/library/time.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,3 +280,64 @@ __CPROVER_size_t _strftime(
280280
s[length] = '\0';
281281
return length;
282282
}
283+
284+
/* FUNCTION: clock_gettime */
285+
286+
#ifndef __CPROVER_TIME_H_INCLUDED
287+
# include <time.h>
288+
# define __CPROVER_TIME_H_INCLUDED
289+
#endif
290+
291+
#ifndef __CPROVER_ERRNO_H_INCLUDED
292+
# include <errno.h>
293+
# define __CPROVER_ERRNO_H_INCLUDED
294+
#endif
295+
296+
int __VERIFIER_nondet_int(void);
297+
time_t __VERIFIER_nondet_time_t(void);
298+
long __VERIFIER_nondet_long(void);
299+
300+
int clock_gettime(clockid_t clockid, struct timespec *tp)
301+
{
302+
__CPROVER_HIDE:;
303+
304+
// Use the clockid parameter (all clock types are modeled the same way)
305+
(void)clockid;
306+
307+
// Check for null pointer - should set errno to EFAULT
308+
if(!tp)
309+
{
310+
errno = EFAULT;
311+
return -1;
312+
}
313+
314+
// Non-deterministically choose success or failure
315+
int result = __VERIFIER_nondet_int();
316+
317+
if(result == 0)
318+
{
319+
// Success case: fill in the timespec structure with non-deterministic but valid values
320+
time_t sec = __VERIFIER_nondet_time_t();
321+
// Assume reasonable time values (non-negative for typical use cases)
322+
__CPROVER_assume(sec >= 0);
323+
tp->tv_sec = sec;
324+
325+
// Nanoseconds should be between 0 and 999,999,999
326+
long nanosec = __VERIFIER_nondet_long();
327+
__CPROVER_assume(nanosec >= 0 && nanosec <= 999999999L);
328+
tp->tv_nsec = nanosec;
329+
330+
return 0;
331+
}
332+
else
333+
{
334+
// Failure case: set errno and return -1
335+
int error_code = __VERIFIER_nondet_int();
336+
// Most common error codes for clock_gettime
337+
__CPROVER_assume(
338+
error_code == EINVAL || error_code == EACCES || error_code == ENODEV ||
339+
error_code == ENOTSUP || error_code == EOVERFLOW || error_code == EPERM);
340+
errno = error_code;
341+
return -1;
342+
}
343+
}

0 commit comments

Comments
 (0)