Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2021 Yubico AB. All rights reserved. |
3 | | * Use of this source code is governed by a BSD-style |
4 | | * license that can be found in the LICENSE file. |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | */ |
7 | | |
8 | | #include <stdint.h> |
9 | | #include <time.h> |
10 | | |
11 | | #include "mutator_aux.h" |
12 | | |
13 | | /* |
14 | | * A pseudo-random monotonic clock with a probabilistic discontinuity to |
15 | | * the end of time (as measured by struct timespec). |
16 | | */ |
17 | | |
18 | | extern int prng_up; |
19 | | extern int __wrap_clock_gettime(clockid_t, struct timespec *); |
20 | | extern int __real_clock_gettime(clockid_t, struct timespec *); |
21 | | extern int __wrap_usleep(unsigned int); |
22 | | static TLS struct timespec fuzz_clock; |
23 | | |
24 | | static void |
25 | | tick(unsigned int usec) |
26 | 783k | { |
27 | 783k | long long drift; |
28 | | |
29 | | /* |
30 | | * Simulate a jump to the end of time with 0.125% probability. |
31 | | * This condition should be gracefully handled by callers of |
32 | | * clock_gettime(). |
33 | | */ |
34 | 783k | if (uniform_random(800) < 1) { |
35 | 1.04k | fuzz_clock.tv_sec = LLONG_MAX; |
36 | 1.04k | fuzz_clock.tv_nsec = LONG_MAX; |
37 | 1.04k | return; |
38 | 1.04k | } |
39 | | |
40 | 782k | drift = usec * 1000LL + (long long)uniform_random(10000000); /* 10ms */ |
41 | 782k | if (LLONG_MAX - drift < (long long)fuzz_clock.tv_nsec) { |
42 | 865 | fuzz_clock_reset(); /* Not much we can do here. */ |
43 | 781k | } else if (drift + (long long)fuzz_clock.tv_nsec < 1000000000) { |
44 | 731k | fuzz_clock.tv_nsec += (long)(drift); |
45 | 731k | } else { |
46 | 50.9k | fuzz_clock.tv_sec += (long)(drift / 1000000000); |
47 | 50.9k | fuzz_clock.tv_nsec += (long)(drift % 1000000000); |
48 | 50.9k | } |
49 | 782k | } |
50 | | |
51 | | int |
52 | | __wrap_clock_gettime(clockid_t clk_id, struct timespec *tp) |
53 | 784k | { |
54 | 784k | if (!prng_up || clk_id != CLOCK_MONOTONIC) |
55 | 0 | return __real_clock_gettime(clk_id, tp); |
56 | 784k | if (uniform_random(400) < 1) |
57 | 1.35k | return -1; |
58 | | |
59 | 783k | tick(0); |
60 | 783k | *tp = fuzz_clock; |
61 | | |
62 | 783k | return 0; |
63 | 784k | } |
64 | | |
65 | | int |
66 | | __wrap_usleep(unsigned int usec) |
67 | 735 | { |
68 | 735 | if (uniform_random(400) < 1) |
69 | 3 | return -1; |
70 | | |
71 | 732 | tick(usec); |
72 | | |
73 | 732 | return 0; |
74 | 735 | } |
75 | | |
76 | | void |
77 | | fuzz_clock_reset(void) |
78 | 17.7k | { |
79 | 17.7k | memset(&fuzz_clock, 0, sizeof(fuzz_clock)); |
80 | 17.7k | } |