blob: 53e0ac3287f53e5576c650183710c63687da31d5 [file] [log] [blame]
Paul Bakker50157ff2016-07-19 14:57:00 +01001/* BEGIN_HEADER */
Gilles Peskine8064bf32017-10-10 19:56:06 +02002
3/* This test module exercises the timing module. One of the expected failure
4 modes is for timers to never expire, which could lead to an infinite loop.
5 The function timing_timer_simple is protected against this failure mode and
6 checks that timers do expire. Other functions will terminate if their
7 timers do expire. Therefore it is recommended to run timing_timer_simple
8 first and run other test functions only if that timing_timer_simple
9 succeeded. */
10
11#include <limits.h>
12
Paul Bakker50157ff2016-07-19 14:57:00 +010013#include "mbedtls/timing.h"
Gilles Peskine8064bf32017-10-10 19:56:06 +020014
15/* Wait this many milliseconds for a short timing test. This duration
16 should be large enough that, in practice, if you read the timer
17 value twice in a row, it won't have jumped by that much. */
18#define TIMING_SHORT_TEST_MS 100
19
20/* A loop that waits TIMING_SHORT_TEST_MS must not take more than this many
21 iterations. This value needs to be large enough to accommodate fast
22 platforms (e.g. at 4GHz and 10 cycles/iteration a CPU can run through 20
23 million iterations in 50ms). The only motivation to keep this value low is
24 to avoid having an infinite loop if the timer functions are not implemented
25 correctly. Ideally this value should be based on the processor speed but we
26 don't have this information! */
27#define TIMING_SHORT_TEST_ITERATIONS_MAX 1e8
28
29/* alarm(0) must fire in no longer than this amount of time. */
30#define TIMING_ALARM_0_DELAY_MS TIMING_SHORT_TEST_MS
31
32static int expected_delay_status( uint32_t int_ms, uint32_t fin_ms,
33 unsigned long actual_ms )
34{
35 return( fin_ms == 0 ? -1 :
36 actual_ms >= fin_ms ? 2 :
37 actual_ms >= int_ms ? 1 :
38 0 );
39}
40
Paul Bakker50157ff2016-07-19 14:57:00 +010041/* END_HEADER */
42
43/* BEGIN_DEPENDENCIES
44 * depends_on:MBEDTLS_TIMING_C
45 * END_DEPENDENCIES
46 */
47
Gilles Peskine8064bf32017-10-10 19:56:06 +020048/* BEGIN_CASE */
49void timing_timer_simple( )
Paul Bakker50157ff2016-07-19 14:57:00 +010050{
Gilles Peskine8064bf32017-10-10 19:56:06 +020051 struct mbedtls_timing_hr_time timer;
52 unsigned long millis = 0;
53 unsigned long new_millis = 0;
54 unsigned long iterations = 0;
55 /* Start the timer. */
56 (void) mbedtls_timing_get_timer( &timer, 1 );
57 /* Busy-wait loop for a few milliseconds. */
58 do
59 {
60 new_millis = mbedtls_timing_get_timer( &timer, 0 );
61 ++iterations;
62 /* Check that the timer didn't go backwards */
63 TEST_ASSERT( new_millis >= millis );
64 millis = new_millis;
65 }
66 while( millis < TIMING_SHORT_TEST_MS &&
67 iterations <= TIMING_SHORT_TEST_ITERATIONS_MAX );
68 /* The wait duration should have been large enough for at least a
69 few runs through the loop, even on the slowest realistic platform. */
70 TEST_ASSERT( iterations >= 2 );
71 /* The wait duration shouldn't have overflowed the iteration count. */
72 TEST_ASSERT( iterations < TIMING_SHORT_TEST_ITERATIONS_MAX );
73 return;
74
75exit:
76 /* No cleanup needed, but show some diagnostic iterations, because timing
77 problems can be hard to reproduce. */
78 mbedtls_fprintf( stdout, " Finished with millis=%lu new_millis=%lu get(timer)<=%lu iterations=%lu\n",
79 millis, new_millis, mbedtls_timing_get_timer( &timer, 0 ),
80 iterations );
Paul Bakker50157ff2016-07-19 14:57:00 +010081}
82/* END_CASE */
Gilles Peskine8064bf32017-10-10 19:56:06 +020083
84/* BEGIN_CASE */
85void timing_timer_reset( )
86{
87 struct mbedtls_timing_hr_time timer;
88 unsigned long millis = 0;
89 unsigned long iterations = 0;
90 /* Start the timer. Timers are always reset to 0. */
91 TEST_ASSERT( mbedtls_timing_get_timer( &timer, 1 ) == 0 );
92 /* Busy-wait loop for a few milliseconds */
93 do
94 {
95 ++iterations;
96 millis = mbedtls_timing_get_timer( &timer, 0 );
97 }
98 while( millis < TIMING_SHORT_TEST_MS );
99
100 /* Reset the timer and check that it has restarted. */
101 TEST_ASSERT( mbedtls_timing_get_timer( &timer, 1 ) == 0 );
102 /* Read the timer immediately after reset. It should be 0 or close
103 to it. */
104 TEST_ASSERT( mbedtls_timing_get_timer( &timer, 0 ) < TIMING_SHORT_TEST_MS );
105 return;
106
107exit:
108 /* No cleanup needed, but show some diagnostic information, because timing
109 problems can be hard to reproduce. */
110 mbedtls_fprintf( stdout, " Finished with millis=%lu get(timer)<=%lu iterations=%lu\n",
111 millis, mbedtls_timing_get_timer( &timer, 0 ),
112 iterations );
113}
114/* END_CASE */
115
116/* BEGIN_CASE */
117void timing_two_timers( int delta )
118{
119 struct mbedtls_timing_hr_time timer1, timer2;
120 unsigned long millis1, millis2;
121
122 /* Start the first timer and wait for a short time. */
123 (void) mbedtls_timing_get_timer( &timer1, 1 );
124 do
125 {
126 millis1 = mbedtls_timing_get_timer( &timer1, 0 );
127 }
128 while( millis1 < TIMING_SHORT_TEST_MS );
129
130 /* Do a short busy-wait, so that the difference between timer1 and timer2
131 doesn't practically always end up being very close to a whole number of
132 milliseconds. */
133 while( delta > 0 )
134 --delta;
135
136 /* Start the second timer and compare it with the first. */
137 mbedtls_timing_get_timer( &timer2, 1 );
138 do
139 {
140 millis1 = mbedtls_timing_get_timer( &timer1, 0 );
141 millis2 = mbedtls_timing_get_timer( &timer2, 0 );
142 /* The first timer should always be ahead of the first. */
143 TEST_ASSERT( millis1 > millis2 );
144 /* The timers shouldn't drift apart, i.e. millis2-millis1 should stay
145 roughly constant, but this is hard to test reliably, especially in
146 a busy environment such as an overloaded continuous integration
147 system, so we don't test it it. */
148 }
149 while( millis2 < TIMING_SHORT_TEST_MS );
150
151 return;
152
153exit:
154 /* No cleanup needed, but show some diagnostic iterations, because timing
155 problems can be hard to reproduce. */
156 mbedtls_fprintf( stdout, " Finished with millis1=%lu get(timer1)<=%lu millis2=%lu get(timer2)<=%lu\n",
157 millis1, mbedtls_timing_get_timer( &timer1, 0 ),
158 millis2, mbedtls_timing_get_timer( &timer2, 0 ) );
159}
160/* END_CASE */
161
162/* BEGIN_CASE */
163void timing_alarm( int seconds )
164{
165 struct mbedtls_timing_hr_time timer;
166 unsigned long millis = 0;
167 /* We check that about the desired number of seconds has elapsed. Be
168 slightly liberal with the lower bound, so as to allow platforms where
169 the alarm (with second resolution) and the timer (with millisecond
170 resolution) are based on different clocks. Be very liberal with the
171 upper bound, because the platform might be busy. */
172 unsigned long millis_min = ( seconds > 0 ?
173 seconds * 900 :
174 0 );
175 unsigned long millis_max = ( seconds > 0 ?
176 seconds * 1100 + 400 :
177 TIMING_ALARM_0_DELAY_MS );
178 unsigned long iterations = 0;
179
180 /* Set an alarm and count how long it takes with a timer. */
181 (void) mbedtls_timing_get_timer( &timer, 1 );
182 mbedtls_set_alarm( seconds );
183
184 if( seconds > 0 )
185 {
186 /* We set the alarm for at least 1 second. It should not have fired
187 immediately, even on a slow and busy platform. */
188 TEST_ASSERT( !mbedtls_timing_alarmed );
189 }
190 /* A 0-second alarm should fire quickly, but we don't guarantee that it
191 fires immediately, so mbedtls_timing_alarmed may or may not be set at
192 this point. */
193
194 /* Busy-wait until the alarm rings */
195 do
196 {
197 ++iterations;
198 millis = mbedtls_timing_get_timer( &timer, 0 );
199 }
200 while( !mbedtls_timing_alarmed && millis <= millis_max );
201
202 TEST_ASSERT( mbedtls_timing_alarmed );
203 TEST_ASSERT( millis >= millis_min );
204 TEST_ASSERT( millis <= millis_max );
205
206 mbedtls_timing_alarmed = 0;
207 return;
208
209exit:
210 /* Show some diagnostic iterations, because timing
211 problems can be hard to reproduce. */
212 mbedtls_fprintf( stdout, " Finished with alarmed=%d millis=%lu get(timer)<=%lu iterations=%lu\n",
213 mbedtls_timing_alarmed,
214 millis, mbedtls_timing_get_timer( &timer, 0 ),
215 iterations );
216 /* Cleanup */
217 mbedtls_timing_alarmed = 0;
218}
219/* END_CASE */
220
221/* BEGIN_CASE */
222void timing_delay( int int_ms, int fin_ms )
223{
224 /* This function assumes that if int_ms is nonzero then it is large
225 enough that we have time to read all timers at least once in an
226 interval of time lasting int_ms milliseconds, and likewise for (fin_ms
227 - int_ms). So don't call it with arguments that are too small. */
228
229 mbedtls_timing_delay_context delay;
230 struct mbedtls_timing_hr_time timer;
231 unsigned long delta; /* delay started between timer=0 and timer=delta */
232 unsigned long before = 0, after = 0;
233 unsigned long iterations = 0;
234 int status = -2;
235 int saw_status_1 = 0;
236 int warn_inconclusive = 0;
237
238 assert( int_ms >= 0 );
239 assert( fin_ms >= 0 );
240
241 /* Start a reference timer. Program a delay, and verify that the status of
242 the delay is consistent with the time given by the reference timer. */
243 (void) mbedtls_timing_get_timer( &timer, 1 );
244 mbedtls_timing_set_delay( &delay, int_ms, fin_ms );
245 /* Set delta to an upper bound for the interval between the start of timer
246 and the start of delay. Reading timer after starting delay gives us an
247 upper bound for the interval, rounded to a 1ms precision. Since this
248 might have been rounded down, but we need an upper bound, we add 1. */
249 delta = mbedtls_timing_get_timer( &timer, 0 ) + 1;
250
251 status = mbedtls_timing_get_delay( &delay );
252 if( fin_ms == 0 )
253 {
254 /* Cancelled timer. Just check the correct status for this case. */
255 TEST_ASSERT( status == -1 );
256 return;
257 }
258
259 /* Initially, none of the delays must be passed yet if they're nonzero.
260 This could fail for very small values of int_ms and fin_ms, where "very
261 small" depends how fast and how busy the platform is. */
262 if( int_ms > 0 )
263 {
264 TEST_ASSERT( status == 0 );
265 }
266 else
267 {
268 TEST_ASSERT( status == 1 );
269 }
270
271 do
272 {
273 unsigned long delay_min, delay_max;
274 int status_min, status_max;
275 ++iterations;
276 before = mbedtls_timing_get_timer( &timer, 0 );
277 status = mbedtls_timing_get_delay( &delay );
278 after = mbedtls_timing_get_timer( &timer, 0 );
279 /* At a time between before and after, the delay's status was status.
280 Check that this is consistent given that the delay was started
281 between times 0 and delta. */
282 delay_min = ( before > delta ? before - delta : 0 );
283 status_min = expected_delay_status( int_ms, fin_ms, delay_min );
284 delay_max = after;
285 status_max = expected_delay_status( int_ms, fin_ms, delay_max );
286 TEST_ASSERT( status >= status_min );
287 TEST_ASSERT( status <= status_max );
288 if( status == 1 )
289 saw_status_1 = 1;
290 }
291 while ( before <= fin_ms + delta && status != 2 );
292
293 /* Since we've waited at least fin_ms, the delay must have fully
294 expired. */
295 TEST_ASSERT( status == 2 );
296
297 /* If the second delay is more than the first, then there must have been a
298 point in time when the first delay was passed but not the second delay.
299 This could fail for very small values of (fin_ms - int_ms), where "very
300 small" depends how fast and how busy the platform is. In practice, this
301 is the test that's most likely to fail on a heavily loaded machine. */
302 if( fin_ms > int_ms )
303 {
304 warn_inconclusive = 1;
305 TEST_ASSERT( saw_status_1 );
306 }
307
308 return;
309
310exit:
311 /* No cleanup needed, but show some diagnostic iterations, because timing
312 problems can be hard to reproduce. */
313 mbedtls_fprintf( stdout, " Finished with delta=%lu before=%lu after=%lu status=%d iterations=%lu\n",
314 delta, before, after, status, iterations );
315 if( warn_inconclusive )
316 mbedtls_fprintf( stdout, " Inconclusive test, try running it on a less heavily loaded machine.\n" );
317 }
318/* END_CASE */