Fix a race condition in drbgtest.c
[openssl.git] / test / asynctest.c
1 /*
2  * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #ifdef _WIN32
11 # include <windows.h>
12 #endif
13
14 #include <stdio.h>
15 #include <string.h>
16 #include <openssl/async.h>
17 #include <openssl/crypto.h>
18
19 static int ctr = 0;
20 static ASYNC_JOB *currjob = NULL;
21
22 static int only_pause(void *args)
23 {
24     ASYNC_pause_job();
25
26     return 1;
27 }
28
29 static int add_two(void *args)
30 {
31     ctr++;
32     ASYNC_pause_job();
33     ctr++;
34
35     return 2;
36 }
37
38 static int save_current(void *args)
39 {
40     currjob = ASYNC_get_current_job();
41     ASYNC_pause_job();
42
43     return 1;
44 }
45
46 #define MAGIC_WAIT_FD   ((OSSL_ASYNC_FD)99)
47 static int waitfd(void *args)
48 {
49     ASYNC_JOB *job;
50     ASYNC_WAIT_CTX *waitctx;
51     job = ASYNC_get_current_job();
52     if (job == NULL)
53         return 0;
54     waitctx = ASYNC_get_wait_ctx(job);
55     if (waitctx == NULL)
56         return 0;
57
58     /* First case: no fd added or removed */
59     ASYNC_pause_job();
60
61     /* Second case: one fd added */
62     if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL))
63         return 0;
64     ASYNC_pause_job();
65
66     /* Third case: all fd removed */
67     if (!ASYNC_WAIT_CTX_clear_fd(waitctx, waitctx))
68         return 0;
69     ASYNC_pause_job();
70
71     /* Last case: fd added and immediately removed */
72     if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL))
73         return 0;
74     if (!ASYNC_WAIT_CTX_clear_fd(waitctx, waitctx))
75         return 0;
76
77     return 1;
78 }
79
80 static int blockpause(void *args)
81 {
82     ASYNC_block_pause();
83     ASYNC_pause_job();
84     ASYNC_unblock_pause();
85     ASYNC_pause_job();
86
87     return 1;
88 }
89
90 static int test_ASYNC_init_thread(void)
91 {
92     ASYNC_JOB *job1 = NULL, *job2 = NULL, *job3 = NULL;
93     int funcret1, funcret2, funcret3;
94     ASYNC_WAIT_CTX *waitctx = NULL;
95
96     if (       !ASYNC_init_thread(2, 0)
97             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
98             || ASYNC_start_job(&job1, waitctx, &funcret1, only_pause, NULL, 0)
99                 != ASYNC_PAUSE
100             || ASYNC_start_job(&job2, waitctx, &funcret2, only_pause, NULL, 0)
101                 != ASYNC_PAUSE
102             || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
103                 != ASYNC_NO_JOBS
104             || ASYNC_start_job(&job1, waitctx, &funcret1, only_pause, NULL, 0)
105                 != ASYNC_FINISH
106             || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
107                 != ASYNC_PAUSE
108             || ASYNC_start_job(&job2, waitctx, &funcret2, only_pause, NULL, 0)
109                 != ASYNC_FINISH
110             || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
111                 != ASYNC_FINISH
112             || funcret1 != 1
113             || funcret2 != 1
114             || funcret3 != 1) {
115         fprintf(stderr, "test_ASYNC_init_thread() failed\n");
116         ASYNC_WAIT_CTX_free(waitctx);
117         ASYNC_cleanup_thread();
118         return 0;
119     }
120
121     ASYNC_WAIT_CTX_free(waitctx);
122     ASYNC_cleanup_thread();
123     return 1;
124 }
125
126 static int test_ASYNC_start_job(void)
127 {
128     ASYNC_JOB *job = NULL;
129     int funcret;
130     ASYNC_WAIT_CTX *waitctx = NULL;
131
132     ctr = 0;
133
134     if (       !ASYNC_init_thread(1, 0)
135             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
136             || ASYNC_start_job(&job, waitctx, &funcret, add_two, NULL, 0)
137                != ASYNC_PAUSE
138             || ctr != 1
139             || ASYNC_start_job(&job, waitctx, &funcret, add_two, NULL, 0)
140                != ASYNC_FINISH
141             || ctr != 2
142             || funcret != 2) {
143         fprintf(stderr, "test_ASYNC_start_job() failed\n");
144         ASYNC_WAIT_CTX_free(waitctx);
145         ASYNC_cleanup_thread();
146         return 0;
147     }
148
149     ASYNC_WAIT_CTX_free(waitctx);
150     ASYNC_cleanup_thread();
151     return 1;
152 }
153
154 static int test_ASYNC_get_current_job(void)
155 {
156     ASYNC_JOB *job = NULL;
157     int funcret;
158     ASYNC_WAIT_CTX *waitctx = NULL;
159
160     currjob = NULL;
161
162     if (       !ASYNC_init_thread(1, 0)
163             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
164             || ASYNC_start_job(&job, waitctx, &funcret, save_current, NULL, 0)
165                 != ASYNC_PAUSE
166             || currjob != job
167             || ASYNC_start_job(&job, waitctx, &funcret, save_current, NULL, 0)
168                 != ASYNC_FINISH
169             || funcret != 1) {
170         fprintf(stderr, "test_ASYNC_get_current_job() failed\n");
171         ASYNC_WAIT_CTX_free(waitctx);
172         ASYNC_cleanup_thread();
173         return 0;
174     }
175
176     ASYNC_WAIT_CTX_free(waitctx);
177     ASYNC_cleanup_thread();
178     return 1;
179 }
180
181 static int test_ASYNC_WAIT_CTX_get_all_fds(void)
182 {
183     ASYNC_JOB *job = NULL;
184     int funcret;
185     ASYNC_WAIT_CTX *waitctx = NULL;
186     OSSL_ASYNC_FD fd = OSSL_BAD_ASYNC_FD, delfd = OSSL_BAD_ASYNC_FD;
187     size_t numfds, numdelfds;
188
189     if (       !ASYNC_init_thread(1, 0)
190             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
191                /* On first run we're not expecting any wait fds */
192             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
193                 != ASYNC_PAUSE
194             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
195             || numfds != 0
196             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
197                                                &numdelfds)
198             || numfds != 0
199             || numdelfds != 0
200                /* On second run we're expecting one added fd */
201             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
202                 != ASYNC_PAUSE
203             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
204             || numfds != 1
205             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, &fd, &numfds)
206             || fd != MAGIC_WAIT_FD
207             || (fd = OSSL_BAD_ASYNC_FD, 0) /* Assign to something else */
208             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
209                                                &numdelfds)
210             || numfds != 1
211             || numdelfds != 0
212             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, &fd, &numfds, NULL,
213                                                &numdelfds)
214             || fd != MAGIC_WAIT_FD
215                /* On third run we expect one deleted fd */
216             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
217                 != ASYNC_PAUSE
218             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
219             || numfds != 0
220             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
221                                                &numdelfds)
222             || numfds != 0
223             || numdelfds != 1
224             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, &delfd,
225                                                &numdelfds)
226             || delfd != MAGIC_WAIT_FD
227             /* On last run we are not expecting any wait fd */
228             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
229                 != ASYNC_FINISH
230             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
231             || numfds != 0
232             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
233                                                &numdelfds)
234             || numfds != 0
235             || numdelfds != 0
236             || funcret != 1) {
237         fprintf(stderr, "test_ASYNC_get_wait_fd() failed\n");
238         ASYNC_WAIT_CTX_free(waitctx);
239         ASYNC_cleanup_thread();
240         return 0;
241     }
242
243     ASYNC_WAIT_CTX_free(waitctx);
244     ASYNC_cleanup_thread();
245     return 1;
246 }
247
248 static int test_ASYNC_block_pause(void)
249 {
250     ASYNC_JOB *job = NULL;
251     int funcret;
252     ASYNC_WAIT_CTX *waitctx = NULL;
253
254     if (       !ASYNC_init_thread(1, 0)
255             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
256             || ASYNC_start_job(&job, waitctx, &funcret, blockpause, NULL, 0)
257                 != ASYNC_PAUSE
258             || ASYNC_start_job(&job, waitctx, &funcret, blockpause, NULL, 0)
259                 != ASYNC_FINISH
260             || funcret != 1) {
261         fprintf(stderr, "test_ASYNC_block_pause() failed\n");
262         ASYNC_WAIT_CTX_free(waitctx);
263         ASYNC_cleanup_thread();
264         return 0;
265     }
266
267     ASYNC_WAIT_CTX_free(waitctx);
268     ASYNC_cleanup_thread();
269     return 1;
270 }
271
272 int main(int argc, char **argv)
273 {
274     if (!ASYNC_is_capable()) {
275         fprintf(stderr,
276                 "OpenSSL build is not ASYNC capable - skipping async tests\n");
277     } else {
278         CRYPTO_set_mem_debug(1);
279         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
280
281         if (       !test_ASYNC_init_thread()
282                 || !test_ASYNC_start_job()
283                 || !test_ASYNC_get_current_job()
284                 || !test_ASYNC_WAIT_CTX_get_all_fds()
285                 || !test_ASYNC_block_pause()) {
286             return 1;
287         }
288     }
289     printf("PASS\n");
290     return 0;
291 }