xref: /freebsd/crypto/openssl/test/testutil/basic_output.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1 /*
2  * Copyright 2017-2025 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (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 #include "../testutil.h"
11 #include "output.h"
12 #include "tu_local.h"
13 
14 #include <openssl/crypto.h>
15 #include <openssl/bio.h>
16 
17 /* These are available for any test program */
18 BIO *bio_out = NULL;
19 BIO *bio_err = NULL;
20 
21 /* These are available for TAP output only (internally) */
22 static BIO *tap_out = NULL;
23 static BIO *tap_err = NULL;
24 
25 typedef struct local_test_data_st {
26     BIO *override_bio_out, *override_bio_err;
27 } LOCAL_TEST_DATA;
28 
29 #if defined(OPENSSL_THREADS)
30 static CRYPTO_THREAD_LOCAL local_test_data; /* (LOCAL_TEST_DATA *) */
31 
32 static CRYPTO_RWLOCK *io_lock = NULL;
33 #endif
34 
35 #if defined(OPENSSL_THREADS)
cleanup_test_data(void * p)36 static void cleanup_test_data(void *p)
37 {
38     OPENSSL_free(p);
39 }
40 #endif
41 
init_local_test_data(void)42 static int init_local_test_data(void)
43 {
44 #if defined(OPENSSL_THREADS)
45     if (!CRYPTO_THREAD_init_local(&local_test_data, cleanup_test_data))
46         return 0;
47 #endif
48 
49     return 1;
50 }
51 
get_local_test_data(void)52 static LOCAL_TEST_DATA *get_local_test_data(void)
53 {
54 #if defined(OPENSSL_THREADS)
55     LOCAL_TEST_DATA *p;
56 
57     p = CRYPTO_THREAD_get_local(&local_test_data);
58     if (p != NULL)
59         return p;
60 
61     if ((p = OPENSSL_zalloc(sizeof(*p))) == NULL)
62         return NULL;
63 
64     if (!CRYPTO_THREAD_set_local(&local_test_data, p)) {
65         OPENSSL_free(p);
66         return NULL;
67     }
68 
69     return p;
70 #else
71     return NULL;
72 #endif
73 }
74 
cleanup_local_test_data(void)75 static void cleanup_local_test_data(void)
76 {
77 #if defined(OPENSSL_THREADS)
78     LOCAL_TEST_DATA *p;
79 
80     p = CRYPTO_THREAD_get_local(&local_test_data);
81     if (p == NULL)
82         return;
83 
84     CRYPTO_THREAD_set_local(&local_test_data, NULL);
85     OPENSSL_free(p);
86 #endif
87 }
88 
set_override_bio_out(BIO * bio)89 int set_override_bio_out(BIO *bio)
90 {
91     LOCAL_TEST_DATA *data = get_local_test_data();
92 
93     if (data == NULL)
94         return 0;
95 
96     data->override_bio_out = bio;
97     return 1;
98 }
99 
set_override_bio_err(BIO * bio)100 int set_override_bio_err(BIO *bio)
101 {
102     LOCAL_TEST_DATA *data = get_local_test_data();
103 
104     if (data == NULL)
105         return 0;
106 
107     data->override_bio_err = bio;
108     return 1;
109 }
110 
get_bio_out(void)111 static BIO *get_bio_out(void)
112 {
113     LOCAL_TEST_DATA *data = get_local_test_data();
114 
115     if (data != NULL && data->override_bio_out != NULL)
116         return data->override_bio_out;
117 
118     return bio_out;
119 }
120 
get_bio_err(void)121 static BIO *get_bio_err(void)
122 {
123     LOCAL_TEST_DATA *data = get_local_test_data();
124 
125     if (data != NULL && data->override_bio_err != NULL)
126         return data->override_bio_err;
127 
128     return bio_err;
129 }
130 
test_open_streams(void)131 void test_open_streams(void)
132 {
133     int ok;
134 
135     ok = init_local_test_data();
136 
137     tap_out = BIO_new_fp(stdout, BIO_NOCLOSE | BIO_FP_TEXT);
138     tap_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
139 #ifdef __VMS
140     tap_out = BIO_push(BIO_new(BIO_f_linebuffer()), tap_out);
141     tap_err = BIO_push(BIO_new(BIO_f_linebuffer()), tap_err);
142 #endif
143     tap_out = BIO_push(BIO_new(BIO_f_prefix()), tap_out);
144     tap_err = BIO_push(BIO_new(BIO_f_prefix()), tap_err);
145 
146     bio_out = BIO_push(BIO_new(BIO_f_prefix()), tap_out);
147     bio_err = BIO_push(BIO_new(BIO_f_prefix()), tap_err);
148     BIO_set_prefix(bio_out, "# ");
149     BIO_set_prefix(bio_err, "# ");
150 
151 #if defined(OPENSSL_THREADS)
152     io_lock = CRYPTO_THREAD_lock_new();
153 #endif
154 
155     OPENSSL_assert(ok);
156     OPENSSL_assert(bio_out != NULL);
157     OPENSSL_assert(bio_err != NULL);
158 #if defined(OPENSSL_THREADS)
159     OPENSSL_assert(io_lock != NULL);
160 #endif
161 }
162 
test_adjust_streams_tap_level(int level)163 void test_adjust_streams_tap_level(int level)
164 {
165     BIO_set_indent(tap_out, level);
166     BIO_set_indent(tap_err, level);
167 }
168 
test_close_streams(void)169 void test_close_streams(void)
170 {
171     /*
172      * The rest of the chain is freed by the BIO_free_all() calls below, so
173      * we only need to free the last one in the bio_out and bio_err chains.
174      */
175     BIO_free(bio_out);
176     BIO_free(bio_err);
177 
178     BIO_free_all(tap_out);
179     BIO_free_all(tap_err);
180 
181     cleanup_local_test_data();
182 
183 #if defined(OPENSSL_THREADS)
184     CRYPTO_THREAD_lock_free(io_lock);
185 #endif
186 }
187 
test_io_lock(void)188 static ossl_inline void test_io_lock(void)
189 {
190 #if defined(OPENSSL_THREADS)
191     OPENSSL_assert(CRYPTO_THREAD_write_lock(io_lock) > 0);
192 #endif
193 }
194 
test_io_unlock(void)195 static ossl_inline void test_io_unlock(void)
196 {
197 #if defined(OPENSSL_THREADS)
198     CRYPTO_THREAD_unlock(io_lock);
199 #endif
200 }
201 
test_vprintf_stdout(const char * fmt,va_list ap)202 int test_vprintf_stdout(const char *fmt, va_list ap)
203 {
204     int r;
205 
206     test_io_lock();
207     r = BIO_vprintf(get_bio_out(), fmt, ap);
208     test_io_unlock();
209 
210     return r;
211 }
212 
test_vprintf_stderr(const char * fmt,va_list ap)213 int test_vprintf_stderr(const char *fmt, va_list ap)
214 {
215     int r;
216 
217     test_io_lock();
218     r = BIO_vprintf(get_bio_err(), fmt, ap);
219     test_io_unlock();
220 
221     return r;
222 }
223 
test_flush_stdout(void)224 int test_flush_stdout(void)
225 {
226     int r;
227 
228     test_io_lock();
229     r = BIO_flush(get_bio_out());
230     test_io_unlock();
231 
232     return r;
233 }
234 
test_flush_stderr(void)235 int test_flush_stderr(void)
236 {
237     int r;
238 
239     test_io_lock();
240     r = BIO_flush(get_bio_err());
241     test_io_unlock();
242 
243     return r;
244 }
245 
test_vprintf_tapout(const char * fmt,va_list ap)246 int test_vprintf_tapout(const char *fmt, va_list ap)
247 {
248     int r;
249 
250     test_io_lock();
251     r = BIO_vprintf(tap_out, fmt, ap);
252     test_io_unlock();
253 
254     return r;
255 }
256 
test_vprintf_taperr(const char * fmt,va_list ap)257 int test_vprintf_taperr(const char *fmt, va_list ap)
258 {
259     int r;
260 
261     test_io_lock();
262     r = BIO_vprintf(tap_err, fmt, ap);
263     test_io_unlock();
264 
265     return r;
266 }
267 
test_flush_tapout(void)268 int test_flush_tapout(void)
269 {
270     int r;
271 
272     test_io_lock();
273     r = BIO_flush(tap_out);
274     test_io_unlock();
275 
276     return r;
277 }
278 
test_flush_taperr(void)279 int test_flush_taperr(void)
280 {
281     int r;
282 
283     test_io_lock();
284     r = BIO_flush(tap_err);
285     test_io_unlock();
286 
287     return r;
288 }
289