Coverage Report

Created: 2025-10-08 19:34

/work/toxcore/mono_time.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: GPL-3.0-or-later
2
 * Copyright © 2016-2025 The TokTok team.
3
 * Copyright © 2014 Tox project.
4
 */
5
#ifndef _XOPEN_SOURCE
6
#define _XOPEN_SOURCE 600
7
#endif /* _XOPEN_SOURCE */
8
9
#if !defined(OS_WIN32) && (defined(_WIN32) || defined(__WIN32__) || defined(WIN32))
10
#define OS_WIN32
11
#endif /* WIN32 */
12
13
#include "mono_time.h"
14
15
#ifdef OS_WIN32
16
#define WIN32_LEAN_AND_MEAN
17
#include <windows.h>
18
#endif /* OS_WIN32 */
19
20
#ifdef __APPLE__
21
#include <mach/clock.h>
22
#include <mach/mach.h>
23
#endif /* __APPLE__ */
24
25
#ifndef OS_WIN32
26
#include <sys/time.h>
27
#endif /* OS_WIN32 */
28
29
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
30
#include <assert.h>
31
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
32
#include <pthread.h>
33
#include <time.h>
34
35
#include "attributes.h"
36
#include "ccompat.h"
37
#include "mem.h"
38
#include "util.h"
39
40
/** don't call into system billions of times for no reason */
41
struct Mono_Time {
42
    uint64_t cur_time;
43
    uint64_t base_time;
44
45
#ifndef ESP_PLATFORM
46
    /* protect `time` from concurrent access */
47
    pthread_rwlock_t *time_update_lock;
48
#endif /* ESP_PLATFORM */
49
50
    mono_time_current_time_cb *current_time_callback;
51
    void *user_data;
52
};
53
54
static uint64_t timespec_to_u64(struct timespec clock_mono)
55
6.06M
{
56
6.06M
    return UINT64_C(1000) * clock_mono.tv_sec + (clock_mono.tv_nsec / UINT64_C(1000000));
57
6.06M
}
58
59
#ifdef OS_WIN32
60
static uint64_t current_time_monotonic_default(void *_Nonnull user_data)
61
{
62
    LARGE_INTEGER freq;
63
    LARGE_INTEGER count;
64
    if (!QueryPerformanceFrequency(&freq)) {
65
        return 0;
66
    }
67
    if (!QueryPerformanceCounter(&count)) {
68
        return 0;
69
    }
70
    struct timespec sp = {0};
71
    sp.tv_sec = count.QuadPart / freq.QuadPart;
72
    if (freq.QuadPart < 1000000000) {
73
        sp.tv_nsec = (count.QuadPart % freq.QuadPart) * 1000000000 / freq.QuadPart;
74
    } else {
75
        sp.tv_nsec = (long)((count.QuadPart % freq.QuadPart) * (1000000000.0 / freq.QuadPart));
76
    }
77
    return timespec_to_u64(sp);
78
}
79
#else
80
#ifdef __APPLE__
81
static uint64_t current_time_monotonic_default(void *_Nonnull user_data)
82
{
83
    struct timespec clock_mono;
84
    clock_serv_t muhclock;
85
    mach_timespec_t machtime;
86
87
    host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &muhclock);
88
    clock_get_time(muhclock, &machtime);
89
    mach_port_deallocate(mach_task_self(), muhclock);
90
91
    clock_mono.tv_sec = machtime.tv_sec;
92
    clock_mono.tv_nsec = machtime.tv_nsec;
93
    return timespec_to_u64(clock_mono);
94
}
95
#else // !__APPLE__
96
static uint64_t current_time_monotonic_default(void *_Nonnull user_data)
97
0
{
98
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
99
    // This assert should always fail. If it does, the fuzzing harness didn't
100
    // override the mono time callback.
101
0
    assert(user_data == nullptr);
102
0
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
103
0
    struct timespec clock_mono;
104
0
    clock_gettime(CLOCK_MONOTONIC, &clock_mono);
105
0
    return timespec_to_u64(clock_mono);
106
0
}
107
#endif /* !__APPLE__ */
108
#endif /* !OS_WIN32 */
109
110
Mono_Time *mono_time_new(const Memory *mem, mono_time_current_time_cb *current_time_callback, void *user_data)
111
7.08k
{
112
7.08k
    Mono_Time *mono_time = (Mono_Time *)mem_alloc(mem, sizeof(Mono_Time));
113
114
7.08k
    if (mono_time == nullptr) {
115
22
        return nullptr;
116
22
    }
117
118
7.06k
#ifndef ESP_PLATFORM
119
7.06k
    pthread_rwlock_t *rwlock = (pthread_rwlock_t *)mem_alloc(mem, sizeof(pthread_rwlock_t));
120
121
7.06k
    if (rwlock == nullptr) {
122
22
        mem_delete(mem, mono_time);
123
22
        return nullptr;
124
22
    }
125
126
7.03k
    if (pthread_rwlock_init(rwlock, nullptr) != 0) {
127
0
        mem_delete(mem, rwlock);
128
0
        mem_delete(mem, mono_time);
129
0
        return nullptr;
130
0
    }
131
132
7.03k
    mono_time->time_update_lock = rwlock;
133
7.03k
#endif /* ESP_PLATFORM */
134
135
7.03k
    mono_time_set_current_time_callback(mono_time, current_time_callback, user_data);
136
137
7.03k
    mono_time->cur_time = 0;
138
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
139
    // Maximum reproducibility. Never return time = 0.
140
    mono_time->base_time = 1000000000;
141
#else
142
    // Never return time = 0 in case time() returns 0 (e.g. on microcontrollers
143
    // without battery-powered RTC or ones where NTP didn't initialise it yet).
144
3.51k
    mono_time->base_time = max_u64(1, (uint64_t)time(nullptr)) * UINT64_C(1000) - current_time_monotonic(mono_time);
145
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
146
147
7.03k
    mono_time_update(mono_time);
148
149
7.03k
    return mono_time;
150
7.03k
}
mono_time_new
Line
Count
Source
111
3.54k
{
112
3.54k
    Mono_Time *mono_time = (Mono_Time *)mem_alloc(mem, sizeof(Mono_Time));
113
114
3.54k
    if (mono_time == nullptr) {
115
11
        return nullptr;
116
11
    }
117
118
3.53k
#ifndef ESP_PLATFORM
119
3.53k
    pthread_rwlock_t *rwlock = (pthread_rwlock_t *)mem_alloc(mem, sizeof(pthread_rwlock_t));
120
121
3.53k
    if (rwlock == nullptr) {
122
11
        mem_delete(mem, mono_time);
123
11
        return nullptr;
124
11
    }
125
126
3.51k
    if (pthread_rwlock_init(rwlock, nullptr) != 0) {
127
0
        mem_delete(mem, rwlock);
128
0
        mem_delete(mem, mono_time);
129
0
        return nullptr;
130
0
    }
131
132
3.51k
    mono_time->time_update_lock = rwlock;
133
3.51k
#endif /* ESP_PLATFORM */
134
135
3.51k
    mono_time_set_current_time_callback(mono_time, current_time_callback, user_data);
136
137
3.51k
    mono_time->cur_time = 0;
138
3.51k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
139
    // Maximum reproducibility. Never return time = 0.
140
3.51k
    mono_time->base_time = 1000000000;
141
#else
142
    // Never return time = 0 in case time() returns 0 (e.g. on microcontrollers
143
    // without battery-powered RTC or ones where NTP didn't initialise it yet).
144
    mono_time->base_time = max_u64(1, (uint64_t)time(nullptr)) * UINT64_C(1000) - current_time_monotonic(mono_time);
145
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
146
147
3.51k
    mono_time_update(mono_time);
148
149
3.51k
    return mono_time;
150
3.51k
}
mono_time_new
Line
Count
Source
111
3.54k
{
112
3.54k
    Mono_Time *mono_time = (Mono_Time *)mem_alloc(mem, sizeof(Mono_Time));
113
114
3.54k
    if (mono_time == nullptr) {
115
11
        return nullptr;
116
11
    }
117
118
3.53k
#ifndef ESP_PLATFORM
119
3.53k
    pthread_rwlock_t *rwlock = (pthread_rwlock_t *)mem_alloc(mem, sizeof(pthread_rwlock_t));
120
121
3.53k
    if (rwlock == nullptr) {
122
11
        mem_delete(mem, mono_time);
123
11
        return nullptr;
124
11
    }
125
126
3.51k
    if (pthread_rwlock_init(rwlock, nullptr) != 0) {
127
0
        mem_delete(mem, rwlock);
128
0
        mem_delete(mem, mono_time);
129
0
        return nullptr;
130
0
    }
131
132
3.51k
    mono_time->time_update_lock = rwlock;
133
3.51k
#endif /* ESP_PLATFORM */
134
135
3.51k
    mono_time_set_current_time_callback(mono_time, current_time_callback, user_data);
136
137
3.51k
    mono_time->cur_time = 0;
138
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
139
    // Maximum reproducibility. Never return time = 0.
140
    mono_time->base_time = 1000000000;
141
#else
142
    // Never return time = 0 in case time() returns 0 (e.g. on microcontrollers
143
    // without battery-powered RTC or ones where NTP didn't initialise it yet).
144
3.51k
    mono_time->base_time = max_u64(1, (uint64_t)time(nullptr)) * UINT64_C(1000) - current_time_monotonic(mono_time);
145
3.51k
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
146
147
3.51k
    mono_time_update(mono_time);
148
149
3.51k
    return mono_time;
150
3.51k
}
151
152
void mono_time_free(const Memory *mem, Mono_Time *mono_time)
153
2.64k
{
154
2.64k
    if (mono_time == nullptr) {
155
0
        return;
156
0
    }
157
2.64k
#ifndef ESP_PLATFORM
158
2.64k
    pthread_rwlock_destroy(mono_time->time_update_lock);
159
2.64k
    mem_delete(mem, mono_time->time_update_lock);
160
2.64k
#endif /* ESP_PLATFORM */
161
2.64k
    mem_delete(mem, mono_time);
162
2.64k
}
163
164
void mono_time_update(Mono_Time *mono_time)
165
5.99M
{
166
5.99M
    const uint64_t cur_time =
167
5.99M
        mono_time->base_time + mono_time->current_time_callback(mono_time->user_data);
168
169
5.99M
#ifndef ESP_PLATFORM
170
5.99M
    pthread_rwlock_wrlock(mono_time->time_update_lock);
171
5.99M
#endif /* ESP_PLATFORM */
172
5.99M
    mono_time->cur_time = cur_time;
173
5.99M
#ifndef ESP_PLATFORM
174
5.99M
    pthread_rwlock_unlock(mono_time->time_update_lock);
175
5.99M
#endif /* ESP_PLATFORM */
176
5.99M
}
177
178
uint64_t mono_time_get_ms(const Mono_Time *mono_time)
179
75.0M
{
180
#if !defined(ESP_PLATFORM) && !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
181
    // Fuzzing is only single thread for now, no locking needed */
182
    pthread_rwlock_rdlock(mono_time->time_update_lock);
183
#endif /* !ESP_PLATFORM */
184
75.0M
    const uint64_t cur_time = mono_time->cur_time;
185
#if !defined(ESP_PLATFORM) && !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
186
    pthread_rwlock_unlock(mono_time->time_update_lock);
187
#endif /* !ESP_PLATFORM */
188
75.0M
    return cur_time;
189
75.0M
}
190
191
uint64_t mono_time_get(const Mono_Time *mono_time)
192
75.0M
{
193
75.0M
    return mono_time_get_ms(mono_time) / UINT64_C(1000);
194
75.0M
}
195
196
bool mono_time_is_timeout(const Mono_Time *mono_time, uint64_t timestamp, uint64_t timeout)
197
64.7M
{
198
64.7M
    return timestamp + timeout <= mono_time_get(mono_time);
199
64.7M
}
200
201
void mono_time_set_current_time_callback(Mono_Time *mono_time,
202
        mono_time_current_time_cb *current_time_callback, void *user_data)
203
5.72k
{
204
5.72k
    if (current_time_callback == nullptr) {
205
2.95k
        mono_time->current_time_callback = current_time_monotonic_default;
206
2.95k
        mono_time->user_data = mono_time;
207
2.95k
    } else {
208
2.76k
        mono_time->current_time_callback = current_time_callback;
209
2.76k
        mono_time->user_data = user_data;
210
2.76k
    }
211
5.72k
}
212
213
/** @brief Return current monotonic time in milliseconds (ms).
214
 *
215
 * The starting point is unspecified and in particular is likely not comparable
216
 * to the return value of `mono_time_get_ms()`.
217
 */
218
uint64_t current_time_monotonic(const Mono_Time *mono_time)
219
515k
{
220
515k
    return mono_time->current_time_callback(mono_time->user_data);
221
515k
}