errtest.c revision 1.1.1.1 1 1.1 christos /*
2 1.1 christos * Copyright 2018-2023 The OpenSSL Project Authors. All Rights Reserved.
3 1.1 christos *
4 1.1 christos * Licensed under the Apache License 2.0 (the "License"). You may not use
5 1.1 christos * this file except in compliance with the License. You can obtain a copy
6 1.1 christos * in the file LICENSE in the source distribution or at
7 1.1 christos * https://www.openssl.org/source/license.html
8 1.1 christos */
9 1.1 christos
10 1.1 christos #include <string.h>
11 1.1 christos #include <openssl/opensslconf.h>
12 1.1 christos #include <openssl/err.h>
13 1.1 christos #include <openssl/macros.h>
14 1.1 christos
15 1.1 christos #include "testutil.h"
16 1.1 christos
17 1.1 christos #if defined(OPENSSL_SYS_WINDOWS)
18 1.1 christos # include <windows.h>
19 1.1 christos #else
20 1.1 christos # include <errno.h>
21 1.1 christos #endif
22 1.1 christos
23 1.1 christos #ifndef OPENSSL_NO_DEPRECATED_3_0
24 1.1 christos # define IS_HEX(ch) ((ch >= '0' && ch <='9') || (ch >= 'A' && ch <='F'))
25 1.1 christos
26 1.1 christos static int test_print_error_format(void)
27 1.1 christos {
28 1.1 christos /* Variables used to construct an error line */
29 1.1 christos char *lib;
30 1.1 christos const char *func = OPENSSL_FUNC;
31 1.1 christos char *reason;
32 1.1 christos # ifdef OPENSSL_NO_ERR
33 1.1 christos char reasonbuf[255];
34 1.1 christos # endif
35 1.1 christos # ifndef OPENSSL_NO_FILENAMES
36 1.1 christos const char *file = OPENSSL_FILE;
37 1.1 christos const int line = OPENSSL_LINE;
38 1.1 christos # else
39 1.1 christos const char *file = "";
40 1.1 christos const int line = 0;
41 1.1 christos # endif
42 1.1 christos /* The format for OpenSSL error lines */
43 1.1 christos const char *expected_format = ":error:%08lX:%s:%s:%s:%s:%d";
44 1.1 christos /*-
45 1.1 christos * ^^ ^^ ^^ ^^ ^^
46 1.1 christos * "library" name --------------------------++ || || || ||
47 1.1 christos * function name ------------------------------++ || || ||
48 1.1 christos * reason string (system error string) -----------++ || ||
49 1.1 christos * file name ----------------------------------------++ ||
50 1.1 christos * line number -----------------------------------------++
51 1.1 christos */
52 1.1 christos char expected[512];
53 1.1 christos
54 1.1 christos char *out = NULL, *p = NULL;
55 1.1 christos int ret = 0, len;
56 1.1 christos BIO *bio = NULL;
57 1.1 christos const int syserr = EPERM;
58 1.1 christos unsigned long errorcode;
59 1.1 christos unsigned long reasoncode;
60 1.1 christos
61 1.1 christos /*
62 1.1 christos * We set a mark here so we can clear the system error that we generate
63 1.1 christos * with ERR_PUT_error(). That is, after all, just a simulation to verify
64 1.1 christos * ERR_print_errors() output, not a real error.
65 1.1 christos */
66 1.1 christos ERR_set_mark();
67 1.1 christos
68 1.1 christos ERR_PUT_error(ERR_LIB_SYS, 0, syserr, file, line);
69 1.1 christos errorcode = ERR_peek_error();
70 1.1 christos reasoncode = ERR_GET_REASON(errorcode);
71 1.1 christos
72 1.1 christos if (!TEST_int_eq(reasoncode, syserr)) {
73 1.1 christos ERR_pop_to_mark();
74 1.1 christos goto err;
75 1.1 christos }
76 1.1 christos
77 1.1 christos # if !defined(OPENSSL_NO_ERR)
78 1.1 christos # if defined(OPENSSL_NO_AUTOERRINIT)
79 1.1 christos lib = "lib(2)";
80 1.1 christos # else
81 1.1 christos lib = "system library";
82 1.1 christos # endif
83 1.1 christos reason = strerror(syserr);
84 1.1 christos # else
85 1.1 christos lib = "lib(2)";
86 1.1 christos BIO_snprintf(reasonbuf, sizeof(reasonbuf), "reason(%lu)", reasoncode);
87 1.1 christos reason = reasonbuf;
88 1.1 christos # endif
89 1.1 christos
90 1.1 christos BIO_snprintf(expected, sizeof(expected), expected_format,
91 1.1 christos errorcode, lib, func, reason, file, line);
92 1.1 christos
93 1.1 christos if (!TEST_ptr(bio = BIO_new(BIO_s_mem())))
94 1.1 christos goto err;
95 1.1 christos
96 1.1 christos ERR_print_errors(bio);
97 1.1 christos
98 1.1 christos if (!TEST_int_gt(len = BIO_get_mem_data(bio, &out), 0))
99 1.1 christos goto err;
100 1.1 christos /* Skip over the variable thread id at the start of the string */
101 1.1 christos for (p = out; *p != ':' && *p != 0; ++p) {
102 1.1 christos if (!TEST_true(IS_HEX(*p)))
103 1.1 christos goto err;
104 1.1 christos }
105 1.1 christos if (!TEST_true(*p != 0)
106 1.1 christos || !TEST_strn_eq(expected, p, strlen(expected)))
107 1.1 christos goto err;
108 1.1 christos
109 1.1 christos ret = 1;
110 1.1 christos err:
111 1.1 christos BIO_free(bio);
112 1.1 christos return ret;
113 1.1 christos }
114 1.1 christos #endif
115 1.1 christos
116 1.1 christos /* Test that querying the error queue preserves the OS error. */
117 1.1 christos static int preserves_system_error(void)
118 1.1 christos {
119 1.1 christos #if defined(OPENSSL_SYS_WINDOWS)
120 1.1 christos SetLastError(ERROR_INVALID_FUNCTION);
121 1.1 christos ERR_get_error();
122 1.1 christos return TEST_int_eq(GetLastError(), ERROR_INVALID_FUNCTION);
123 1.1 christos #else
124 1.1 christos errno = EINVAL;
125 1.1 christos ERR_get_error();
126 1.1 christos return TEST_int_eq(errno, EINVAL);
127 1.1 christos #endif
128 1.1 christos }
129 1.1 christos
130 1.1 christos /* Test that calls to ERR_add_error_[v]data append */
131 1.1 christos static int vdata_appends(void)
132 1.1 christos {
133 1.1 christos const char *data;
134 1.1 christos
135 1.1 christos ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
136 1.1 christos ERR_add_error_data(1, "hello ");
137 1.1 christos ERR_add_error_data(1, "world");
138 1.1 christos ERR_peek_error_data(&data, NULL);
139 1.1 christos return TEST_str_eq(data, "hello world");
140 1.1 christos }
141 1.1 christos
142 1.1 christos static int raised_error(void)
143 1.1 christos {
144 1.1 christos const char *f, *data;
145 1.1 christos int l;
146 1.1 christos unsigned long e;
147 1.1 christos
148 1.1 christos /*
149 1.1 christos * When OPENSSL_NO_ERR or OPENSSL_NO_FILENAMES, no file name or line
150 1.1 christos * number is saved, so no point checking them.
151 1.1 christos */
152 1.1 christos #if !defined(OPENSSL_NO_FILENAMES) && !defined(OPENSSL_NO_ERR)
153 1.1 christos const char *file;
154 1.1 christos int line;
155 1.1 christos
156 1.1 christos file = __FILE__;
157 1.1 christos line = __LINE__ + 2; /* The error is generated on the ERR_raise_data line */
158 1.1 christos #endif
159 1.1 christos ERR_raise_data(ERR_LIB_NONE, ERR_R_INTERNAL_ERROR,
160 1.1 christos "calling exit()");
161 1.1 christos if (!TEST_ulong_ne(e = ERR_get_error_all(&f, &l, NULL, &data, NULL), 0)
162 1.1 christos || !TEST_int_eq(ERR_GET_REASON(e), ERR_R_INTERNAL_ERROR)
163 1.1 christos #if !defined(OPENSSL_NO_FILENAMES) && !defined(OPENSSL_NO_ERR)
164 1.1 christos || !TEST_int_eq(l, line)
165 1.1 christos || !TEST_str_eq(f, file)
166 1.1 christos #endif
167 1.1 christos || !TEST_str_eq(data, "calling exit()"))
168 1.1 christos return 0;
169 1.1 christos return 1;
170 1.1 christos }
171 1.1 christos
172 1.1 christos static int test_marks(void)
173 1.1 christos {
174 1.1 christos unsigned long mallocfail, shouldnot;
175 1.1 christos
176 1.1 christos /* Set an initial error */
177 1.1 christos ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
178 1.1 christos mallocfail = ERR_peek_last_error();
179 1.1 christos if (!TEST_ulong_gt(mallocfail, 0))
180 1.1 christos return 0;
181 1.1 christos
182 1.1 christos /* Setting and clearing a mark should not affect the error */
183 1.1 christos if (!TEST_true(ERR_set_mark())
184 1.1 christos || !TEST_true(ERR_pop_to_mark())
185 1.1 christos || !TEST_ulong_eq(mallocfail, ERR_peek_last_error())
186 1.1 christos || !TEST_true(ERR_set_mark())
187 1.1 christos || !TEST_true(ERR_clear_last_mark())
188 1.1 christos || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
189 1.1 christos return 0;
190 1.1 christos
191 1.1 christos /* Test popping errors */
192 1.1 christos if (!TEST_true(ERR_set_mark()))
193 1.1 christos return 0;
194 1.1 christos ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
195 1.1 christos if (!TEST_ulong_ne(mallocfail, ERR_peek_last_error())
196 1.1 christos || !TEST_true(ERR_pop_to_mark())
197 1.1 christos || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
198 1.1 christos return 0;
199 1.1 christos
200 1.1 christos /* Nested marks should also work */
201 1.1 christos if (!TEST_true(ERR_set_mark())
202 1.1 christos || !TEST_true(ERR_set_mark()))
203 1.1 christos return 0;
204 1.1 christos ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
205 1.1 christos if (!TEST_ulong_ne(mallocfail, ERR_peek_last_error())
206 1.1 christos || !TEST_true(ERR_pop_to_mark())
207 1.1 christos || !TEST_true(ERR_pop_to_mark())
208 1.1 christos || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
209 1.1 christos return 0;
210 1.1 christos
211 1.1 christos if (!TEST_true(ERR_set_mark()))
212 1.1 christos return 0;
213 1.1 christos ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
214 1.1 christos shouldnot = ERR_peek_last_error();
215 1.1 christos if (!TEST_ulong_ne(mallocfail, shouldnot)
216 1.1 christos || !TEST_true(ERR_set_mark()))
217 1.1 christos return 0;
218 1.1 christos ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
219 1.1 christos if (!TEST_ulong_ne(shouldnot, ERR_peek_last_error())
220 1.1 christos || !TEST_true(ERR_pop_to_mark())
221 1.1 christos || !TEST_ulong_eq(shouldnot, ERR_peek_last_error())
222 1.1 christos || !TEST_true(ERR_pop_to_mark())
223 1.1 christos || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
224 1.1 christos return 0;
225 1.1 christos
226 1.1 christos /* Setting and clearing a mark should not affect the errors on the stack */
227 1.1 christos if (!TEST_true(ERR_set_mark()))
228 1.1 christos return 0;
229 1.1 christos ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
230 1.1 christos if (!TEST_true(ERR_clear_last_mark())
231 1.1 christos || !TEST_ulong_eq(shouldnot, ERR_peek_last_error()))
232 1.1 christos return 0;
233 1.1 christos
234 1.1 christos /*
235 1.1 christos * Popping where no mark has been set should pop everything - but return
236 1.1 christos * a failure result
237 1.1 christos */
238 1.1 christos if (!TEST_false(ERR_pop_to_mark())
239 1.1 christos || !TEST_ulong_eq(0, ERR_peek_last_error()))
240 1.1 christos return 0;
241 1.1 christos
242 1.1 christos /* Clearing where there is no mark should fail */
243 1.1 christos ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
244 1.1 christos if (!TEST_false(ERR_clear_last_mark())
245 1.1 christos /* "get" the last error to remove it */
246 1.1 christos || !TEST_ulong_eq(mallocfail, ERR_get_error())
247 1.1 christos || !TEST_ulong_eq(0, ERR_peek_last_error()))
248 1.1 christos return 0;
249 1.1 christos
250 1.1 christos /*
251 1.1 christos * Setting a mark where there are no errors in the stack should fail.
252 1.1 christos * NOTE: This is somewhat surprising behaviour but is historically how this
253 1.1 christos * function behaves. In practice we typically set marks without first
254 1.1 christos * checking whether there is anything on the stack - but we also don't
255 1.1 christos * tend to check the success of this function. It turns out to work anyway
256 1.1 christos * because although setting a mark with no errors fails, a subsequent call
257 1.1 christos * to ERR_pop_to_mark() or ERR_clear_last_mark() will do the right thing
258 1.1 christos * anyway (even though they will report a failure result).
259 1.1 christos */
260 1.1 christos if (!TEST_false(ERR_set_mark()))
261 1.1 christos return 0;
262 1.1 christos
263 1.1 christos ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
264 1.1 christos if (!TEST_true(ERR_set_mark()))
265 1.1 christos return 0;
266 1.1 christos ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
267 1.1 christos ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
268 1.1 christos
269 1.1 christos /* Should be able to "pop" past 2 errors */
270 1.1 christos if (!TEST_true(ERR_pop_to_mark())
271 1.1 christos || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
272 1.1 christos return 0;
273 1.1 christos
274 1.1 christos if (!TEST_true(ERR_set_mark()))
275 1.1 christos return 0;
276 1.1 christos ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
277 1.1 christos ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
278 1.1 christos
279 1.1 christos /* Should be able to "clear" past 2 errors */
280 1.1 christos if (!TEST_true(ERR_clear_last_mark())
281 1.1 christos || !TEST_ulong_eq(shouldnot, ERR_peek_last_error()))
282 1.1 christos return 0;
283 1.1 christos
284 1.1 christos /* Clear remaining errors from last test */
285 1.1 christos ERR_clear_error();
286 1.1 christos
287 1.1 christos return 1;
288 1.1 christos }
289 1.1 christos
290 1.1 christos static int test_clear_error(void)
291 1.1 christos {
292 1.1 christos int flags = -1;
293 1.1 christos const char *data = NULL;
294 1.1 christos int res = 0;
295 1.1 christos
296 1.1 christos /* Raise an error with data and clear it */
297 1.1 christos ERR_raise_data(0, 0, "hello %s", "world");
298 1.1 christos ERR_peek_error_data(&data, &flags);
299 1.1 christos if (!TEST_str_eq(data, "hello world")
300 1.1 christos || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
301 1.1 christos goto err;
302 1.1 christos ERR_clear_error();
303 1.1 christos
304 1.1 christos /* Raise a new error without data */
305 1.1 christos ERR_raise(0, 0);
306 1.1 christos ERR_peek_error_data(&data, &flags);
307 1.1 christos if (!TEST_str_eq(data, "")
308 1.1 christos || !TEST_int_eq(flags, ERR_TXT_MALLOCED))
309 1.1 christos goto err;
310 1.1 christos ERR_clear_error();
311 1.1 christos
312 1.1 christos /* Raise a new error with data */
313 1.1 christos ERR_raise_data(0, 0, "goodbye %s world", "cruel");
314 1.1 christos ERR_peek_error_data(&data, &flags);
315 1.1 christos if (!TEST_str_eq(data, "goodbye cruel world")
316 1.1 christos || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
317 1.1 christos goto err;
318 1.1 christos ERR_clear_error();
319 1.1 christos
320 1.1 christos /*
321 1.1 christos * Raise a new error without data to check that the malloced storage
322 1.1 christos * is freed properly
323 1.1 christos */
324 1.1 christos ERR_raise(0, 0);
325 1.1 christos ERR_peek_error_data(&data, &flags);
326 1.1 christos if (!TEST_str_eq(data, "")
327 1.1 christos || !TEST_int_eq(flags, ERR_TXT_MALLOCED))
328 1.1 christos goto err;
329 1.1 christos ERR_clear_error();
330 1.1 christos
331 1.1 christos res = 1;
332 1.1 christos err:
333 1.1 christos ERR_clear_error();
334 1.1 christos return res;
335 1.1 christos }
336 1.1 christos
337 1.1 christos /*
338 1.1 christos * Test saving and restoring error state.
339 1.1 christos * Test 0: Save using OSSL_ERR_STATE_save()
340 1.1 christos * Test 1: Save using OSSL_ERR_STATE_save_to_mark()
341 1.1 christos */
342 1.1 christos static int test_save_restore(int idx)
343 1.1 christos {
344 1.1 christos ERR_STATE *es;
345 1.1 christos int res = 0, i, flags = -1;
346 1.1 christos unsigned long mallocfail, interr;
347 1.1 christos static const char testdata[] = "test data";
348 1.1 christos const char *data = NULL;
349 1.1 christos
350 1.1 christos if (!TEST_ptr(es = OSSL_ERR_STATE_new()))
351 1.1 christos goto err;
352 1.1 christos
353 1.1 christos ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
354 1.1 christos mallocfail = ERR_peek_last_error();
355 1.1 christos if (!TEST_ulong_gt(mallocfail, 0))
356 1.1 christos goto err;
357 1.1 christos
358 1.1 christos if (idx == 1 && !TEST_int_eq(ERR_set_mark(), 1))
359 1.1 christos goto err;
360 1.1 christos
361 1.1 christos ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR, testdata);
362 1.1 christos interr = ERR_peek_last_error();
363 1.1 christos if (!TEST_ulong_ne(mallocfail, ERR_peek_last_error()))
364 1.1 christos goto err;
365 1.1 christos
366 1.1 christos if (idx == 0) {
367 1.1 christos OSSL_ERR_STATE_save(es);
368 1.1 christos
369 1.1 christos if (!TEST_ulong_eq(ERR_peek_last_error(), 0))
370 1.1 christos goto err;
371 1.1 christos } else {
372 1.1 christos OSSL_ERR_STATE_save_to_mark(es);
373 1.1 christos
374 1.1 christos if (!TEST_ulong_ne(ERR_peek_last_error(), 0))
375 1.1 christos goto err;
376 1.1 christos }
377 1.1 christos
378 1.1 christos for (i = 0; i < 2; i++) {
379 1.1 christos OSSL_ERR_STATE_restore(es);
380 1.1 christos
381 1.1 christos if (!TEST_ulong_eq(ERR_peek_last_error(), interr))
382 1.1 christos goto err;
383 1.1 christos ERR_peek_last_error_data(&data, &flags);
384 1.1 christos if (!TEST_str_eq(data, testdata)
385 1.1 christos || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
386 1.1 christos goto err;
387 1.1 christos
388 1.1 christos /* restore again to duplicate the entries */
389 1.1 christos OSSL_ERR_STATE_restore(es);
390 1.1 christos
391 1.1 christos /* verify them all */
392 1.1 christos if (idx == 0 || i == 0) {
393 1.1 christos if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL,
394 1.1 christos &data, &flags), mallocfail)
395 1.1 christos || !TEST_int_ne(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
396 1.1 christos goto err;
397 1.1 christos }
398 1.1 christos
399 1.1 christos if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL,
400 1.1 christos &data, &flags), interr)
401 1.1 christos || !TEST_str_eq(data, testdata)
402 1.1 christos || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
403 1.1 christos goto err;
404 1.1 christos
405 1.1 christos if (idx == 0) {
406 1.1 christos if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL,
407 1.1 christos &data, &flags), mallocfail)
408 1.1 christos || !TEST_int_ne(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
409 1.1 christos goto err;
410 1.1 christos }
411 1.1 christos
412 1.1 christos if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL,
413 1.1 christos &data, &flags), interr)
414 1.1 christos || !TEST_str_eq(data, testdata)
415 1.1 christos || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
416 1.1 christos goto err;
417 1.1 christos
418 1.1 christos if (!TEST_ulong_eq(ERR_get_error(), 0))
419 1.1 christos goto err;
420 1.1 christos }
421 1.1 christos
422 1.1 christos res = 1;
423 1.1 christos err:
424 1.1 christos OSSL_ERR_STATE_free(es);
425 1.1 christos return res;
426 1.1 christos }
427 1.1 christos
428 1.1 christos int setup_tests(void)
429 1.1 christos {
430 1.1 christos ADD_TEST(preserves_system_error);
431 1.1 christos ADD_TEST(vdata_appends);
432 1.1 christos ADD_TEST(raised_error);
433 1.1 christos #ifndef OPENSSL_NO_DEPRECATED_3_0
434 1.1 christos ADD_TEST(test_print_error_format);
435 1.1 christos #endif
436 1.1 christos ADD_TEST(test_marks);
437 1.1 christos ADD_ALL_TESTS(test_save_restore, 2);
438 1.1 christos ADD_TEST(test_clear_error);
439 1.1 christos return 1;
440 1.1 christos }
441