OLD | NEW |
| (Empty) |
1 /* crypto/err/err.c */ | |
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | |
3 * All rights reserved. | |
4 * | |
5 * This package is an SSL implementation written | |
6 * by Eric Young (eay@cryptsoft.com). | |
7 * The implementation was written so as to conform with Netscapes SSL. | |
8 * | |
9 * This library is free for commercial and non-commercial use as long as | |
10 * the following conditions are aheared to. The following conditions | |
11 * apply to all code found in this distribution, be it the RC4, RSA, | |
12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation | |
13 * included with this distribution is covered by the same copyright terms | |
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). | |
15 * | |
16 * Copyright remains Eric Young's, and as such any Copyright notices in | |
17 * the code are not to be removed. | |
18 * If this package is used in a product, Eric Young should be given attribution | |
19 * as the author of the parts of the library used. | |
20 * This can be in the form of a textual message at program startup or | |
21 * in documentation (online or textual) provided with the package. | |
22 * | |
23 * Redistribution and use in source and binary forms, with or without | |
24 * modification, are permitted provided that the following conditions | |
25 * are met: | |
26 * 1. Redistributions of source code must retain the copyright | |
27 * notice, this list of conditions and the following disclaimer. | |
28 * 2. Redistributions in binary form must reproduce the above copyright | |
29 * notice, this list of conditions and the following disclaimer in the | |
30 * documentation and/or other materials provided with the distribution. | |
31 * 3. All advertising materials mentioning features or use of this software | |
32 * must display the following acknowledgement: | |
33 * "This product includes cryptographic software written by | |
34 * Eric Young (eay@cryptsoft.com)" | |
35 * The word 'cryptographic' can be left out if the rouines from the library | |
36 * being used are not cryptographic related :-). | |
37 * 4. If you include any Windows specific code (or a derivative thereof) from | |
38 * the apps directory (application code) you must include an acknowledgement: | |
39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" | |
40 * | |
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND | |
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
51 * SUCH DAMAGE. | |
52 * | |
53 * The licence and distribution terms for any publically available version or | |
54 * derivative of this code cannot be changed. i.e. this code cannot simply be | |
55 * copied and put under another distribution licence | |
56 * [including the GNU Public Licence.] | |
57 */ | |
58 /* ==================================================================== | |
59 * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. | |
60 * | |
61 * Redistribution and use in source and binary forms, with or without | |
62 * modification, are permitted provided that the following conditions | |
63 * are met: | |
64 * | |
65 * 1. Redistributions of source code must retain the above copyright | |
66 * notice, this list of conditions and the following disclaimer. | |
67 * | |
68 * 2. Redistributions in binary form must reproduce the above copyright | |
69 * notice, this list of conditions and the following disclaimer in | |
70 * the documentation and/or other materials provided with the | |
71 * distribution. | |
72 * | |
73 * 3. All advertising materials mentioning features or use of this | |
74 * software must display the following acknowledgment: | |
75 * "This product includes software developed by the OpenSSL Project | |
76 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" | |
77 * | |
78 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | |
79 * endorse or promote products derived from this software without | |
80 * prior written permission. For written permission, please contact | |
81 * openssl-core@openssl.org. | |
82 * | |
83 * 5. Products derived from this software may not be called "OpenSSL" | |
84 * nor may "OpenSSL" appear in their names without prior written | |
85 * permission of the OpenSSL Project. | |
86 * | |
87 * 6. Redistributions of any form whatsoever must retain the following | |
88 * acknowledgment: | |
89 * "This product includes software developed by the OpenSSL Project | |
90 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" | |
91 * | |
92 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | |
93 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
94 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
95 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR | |
96 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
97 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
98 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
99 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
100 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
101 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
102 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
103 * OF THE POSSIBILITY OF SUCH DAMAGE. | |
104 * ==================================================================== | |
105 * | |
106 * This product includes cryptographic software written by Eric Young | |
107 * (eay@cryptsoft.com). This product includes software written by Tim | |
108 * Hudson (tjh@cryptsoft.com). | |
109 * | |
110 */ | |
111 | |
112 #include <stdio.h> | |
113 #include <stdarg.h> | |
114 #include <string.h> | |
115 #include "cryptlib.h" | |
116 #include <openssl/lhash.h> | |
117 #include <openssl/crypto.h> | |
118 #include <openssl/buffer.h> | |
119 #include <openssl/bio.h> | |
120 #include <openssl/err.h> | |
121 | |
122 DECLARE_LHASH_OF(ERR_STRING_DATA); | |
123 DECLARE_LHASH_OF(ERR_STATE); | |
124 | |
125 static void err_load_strings(int lib, ERR_STRING_DATA *str); | |
126 | |
127 static void ERR_STATE_free(ERR_STATE *s); | |
128 #ifndef OPENSSL_NO_ERR | |
129 static ERR_STRING_DATA ERR_str_libraries[]= | |
130 { | |
131 {ERR_PACK(ERR_LIB_NONE,0,0) ,"unknown library"}, | |
132 {ERR_PACK(ERR_LIB_SYS,0,0) ,"system library"}, | |
133 {ERR_PACK(ERR_LIB_BN,0,0) ,"bignum routines"}, | |
134 {ERR_PACK(ERR_LIB_RSA,0,0) ,"rsa routines"}, | |
135 {ERR_PACK(ERR_LIB_DH,0,0) ,"Diffie-Hellman routines"}, | |
136 {ERR_PACK(ERR_LIB_EVP,0,0) ,"digital envelope routines"}, | |
137 {ERR_PACK(ERR_LIB_BUF,0,0) ,"memory buffer routines"}, | |
138 {ERR_PACK(ERR_LIB_OBJ,0,0) ,"object identifier routines"}, | |
139 {ERR_PACK(ERR_LIB_PEM,0,0) ,"PEM routines"}, | |
140 {ERR_PACK(ERR_LIB_DSA,0,0) ,"dsa routines"}, | |
141 {ERR_PACK(ERR_LIB_X509,0,0) ,"x509 certificate routines"}, | |
142 {ERR_PACK(ERR_LIB_ASN1,0,0) ,"asn1 encoding routines"}, | |
143 {ERR_PACK(ERR_LIB_CONF,0,0) ,"configuration file routines"}, | |
144 {ERR_PACK(ERR_LIB_CRYPTO,0,0) ,"common libcrypto routines"}, | |
145 {ERR_PACK(ERR_LIB_EC,0,0) ,"elliptic curve routines"}, | |
146 {ERR_PACK(ERR_LIB_SSL,0,0) ,"SSL routines"}, | |
147 {ERR_PACK(ERR_LIB_BIO,0,0) ,"BIO routines"}, | |
148 {ERR_PACK(ERR_LIB_PKCS7,0,0) ,"PKCS7 routines"}, | |
149 {ERR_PACK(ERR_LIB_X509V3,0,0) ,"X509 V3 routines"}, | |
150 {ERR_PACK(ERR_LIB_PKCS12,0,0) ,"PKCS12 routines"}, | |
151 {ERR_PACK(ERR_LIB_RAND,0,0) ,"random number generator"}, | |
152 {ERR_PACK(ERR_LIB_DSO,0,0) ,"DSO support routines"}, | |
153 {ERR_PACK(ERR_LIB_TS,0,0) ,"time stamp routines"}, | |
154 {ERR_PACK(ERR_LIB_ENGINE,0,0) ,"engine routines"}, | |
155 {ERR_PACK(ERR_LIB_OCSP,0,0) ,"OCSP routines"}, | |
156 {ERR_PACK(ERR_LIB_FIPS,0,0) ,"FIPS routines"}, | |
157 {ERR_PACK(ERR_LIB_CMS,0,0) ,"CMS routines"}, | |
158 {ERR_PACK(ERR_LIB_HMAC,0,0) ,"HMAC routines"}, | |
159 {0,NULL}, | |
160 }; | |
161 | |
162 static ERR_STRING_DATA ERR_str_functs[]= | |
163 { | |
164 {ERR_PACK(0,SYS_F_FOPEN,0), "fopen"}, | |
165 {ERR_PACK(0,SYS_F_CONNECT,0), "connect"}, | |
166 {ERR_PACK(0,SYS_F_GETSERVBYNAME,0), "getservbyname"}, | |
167 {ERR_PACK(0,SYS_F_SOCKET,0), "socket"}, | |
168 {ERR_PACK(0,SYS_F_IOCTLSOCKET,0), "ioctlsocket"}, | |
169 {ERR_PACK(0,SYS_F_BIND,0), "bind"}, | |
170 {ERR_PACK(0,SYS_F_LISTEN,0), "listen"}, | |
171 {ERR_PACK(0,SYS_F_ACCEPT,0), "accept"}, | |
172 #ifdef OPENSSL_SYS_WINDOWS | |
173 {ERR_PACK(0,SYS_F_WSASTARTUP,0), "WSAstartup"}, | |
174 #endif | |
175 {ERR_PACK(0,SYS_F_OPENDIR,0), "opendir"}, | |
176 {ERR_PACK(0,SYS_F_FREAD,0), "fread"}, | |
177 {0,NULL}, | |
178 }; | |
179 | |
180 static ERR_STRING_DATA ERR_str_reasons[]= | |
181 { | |
182 {ERR_R_SYS_LIB ,"system lib"}, | |
183 {ERR_R_BN_LIB ,"BN lib"}, | |
184 {ERR_R_RSA_LIB ,"RSA lib"}, | |
185 {ERR_R_DH_LIB ,"DH lib"}, | |
186 {ERR_R_EVP_LIB ,"EVP lib"}, | |
187 {ERR_R_BUF_LIB ,"BUF lib"}, | |
188 {ERR_R_OBJ_LIB ,"OBJ lib"}, | |
189 {ERR_R_PEM_LIB ,"PEM lib"}, | |
190 {ERR_R_DSA_LIB ,"DSA lib"}, | |
191 {ERR_R_X509_LIB ,"X509 lib"}, | |
192 {ERR_R_ASN1_LIB ,"ASN1 lib"}, | |
193 {ERR_R_CONF_LIB ,"CONF lib"}, | |
194 {ERR_R_CRYPTO_LIB ,"CRYPTO lib"}, | |
195 {ERR_R_EC_LIB ,"EC lib"}, | |
196 {ERR_R_SSL_LIB ,"SSL lib"}, | |
197 {ERR_R_BIO_LIB ,"BIO lib"}, | |
198 {ERR_R_PKCS7_LIB ,"PKCS7 lib"}, | |
199 {ERR_R_X509V3_LIB ,"X509V3 lib"}, | |
200 {ERR_R_PKCS12_LIB ,"PKCS12 lib"}, | |
201 {ERR_R_RAND_LIB ,"RAND lib"}, | |
202 {ERR_R_DSO_LIB ,"DSO lib"}, | |
203 {ERR_R_ENGINE_LIB ,"ENGINE lib"}, | |
204 {ERR_R_OCSP_LIB ,"OCSP lib"}, | |
205 {ERR_R_TS_LIB ,"TS lib"}, | |
206 | |
207 {ERR_R_NESTED_ASN1_ERROR ,"nested asn1 error"}, | |
208 {ERR_R_BAD_ASN1_OBJECT_HEADER ,"bad asn1 object header"}, | |
209 {ERR_R_BAD_GET_ASN1_OBJECT_CALL ,"bad get asn1 object call"}, | |
210 {ERR_R_EXPECTING_AN_ASN1_SEQUENCE ,"expecting an asn1 sequence"}, | |
211 {ERR_R_ASN1_LENGTH_MISMATCH ,"asn1 length mismatch"}, | |
212 {ERR_R_MISSING_ASN1_EOS ,"missing asn1 eos"}, | |
213 | |
214 {ERR_R_FATAL ,"fatal"}, | |
215 {ERR_R_MALLOC_FAILURE ,"malloc failure"}, | |
216 {ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED ,"called a function you should not call"
}, | |
217 {ERR_R_PASSED_NULL_PARAMETER ,"passed a null parameter"}, | |
218 {ERR_R_INTERNAL_ERROR ,"internal error"}, | |
219 {ERR_R_DISABLED ,"called a function that was disabled at
compile-time"}, | |
220 | |
221 {0,NULL}, | |
222 }; | |
223 #endif | |
224 | |
225 | |
226 /* Define the predeclared (but externally opaque) "ERR_FNS" type */ | |
227 struct st_ERR_FNS | |
228 { | |
229 /* Works on the "error_hash" string table */ | |
230 LHASH_OF(ERR_STRING_DATA) *(*cb_err_get)(int create); | |
231 void (*cb_err_del)(void); | |
232 ERR_STRING_DATA *(*cb_err_get_item)(const ERR_STRING_DATA *); | |
233 ERR_STRING_DATA *(*cb_err_set_item)(ERR_STRING_DATA *); | |
234 ERR_STRING_DATA *(*cb_err_del_item)(ERR_STRING_DATA *); | |
235 /* Works on the "thread_hash" error-state table */ | |
236 LHASH_OF(ERR_STATE) *(*cb_thread_get)(int create); | |
237 void (*cb_thread_release)(LHASH_OF(ERR_STATE) **hash); | |
238 ERR_STATE *(*cb_thread_get_item)(const ERR_STATE *); | |
239 ERR_STATE *(*cb_thread_set_item)(ERR_STATE *); | |
240 void (*cb_thread_del_item)(const ERR_STATE *); | |
241 /* Returns the next available error "library" numbers */ | |
242 int (*cb_get_next_lib)(void); | |
243 }; | |
244 | |
245 /* Predeclarations of the "err_defaults" functions */ | |
246 static LHASH_OF(ERR_STRING_DATA) *int_err_get(int create); | |
247 static void int_err_del(void); | |
248 static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *); | |
249 static ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *); | |
250 static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *); | |
251 static LHASH_OF(ERR_STATE) *int_thread_get(int create); | |
252 static void int_thread_release(LHASH_OF(ERR_STATE) **hash); | |
253 static ERR_STATE *int_thread_get_item(const ERR_STATE *); | |
254 static ERR_STATE *int_thread_set_item(ERR_STATE *); | |
255 static void int_thread_del_item(const ERR_STATE *); | |
256 static int int_err_get_next_lib(void); | |
257 /* The static ERR_FNS table using these defaults functions */ | |
258 static const ERR_FNS err_defaults = | |
259 { | |
260 int_err_get, | |
261 int_err_del, | |
262 int_err_get_item, | |
263 int_err_set_item, | |
264 int_err_del_item, | |
265 int_thread_get, | |
266 int_thread_release, | |
267 int_thread_get_item, | |
268 int_thread_set_item, | |
269 int_thread_del_item, | |
270 int_err_get_next_lib | |
271 }; | |
272 | |
273 /* The replacable table of ERR_FNS functions we use at run-time */ | |
274 static const ERR_FNS *err_fns = NULL; | |
275 | |
276 /* Eg. rather than using "err_get()", use "ERRFN(err_get)()". */ | |
277 #define ERRFN(a) err_fns->cb_##a | |
278 | |
279 /* The internal state used by "err_defaults" - as such, the setting, reading, | |
280 * creating, and deleting of this data should only be permitted via the | |
281 * "err_defaults" functions. This way, a linked module can completely defer all | |
282 * ERR state operation (together with requisite locking) to the implementations | |
283 * and state in the loading application. */ | |
284 static LHASH_OF(ERR_STRING_DATA) *int_error_hash = NULL; | |
285 static LHASH_OF(ERR_STATE) *int_thread_hash = NULL; | |
286 static int int_thread_hash_references = 0; | |
287 static int int_err_library_number= ERR_LIB_USER; | |
288 | |
289 /* Internal function that checks whether "err_fns" is set and if not, sets it to | |
290 * the defaults. */ | |
291 static void err_fns_check(void) | |
292 { | |
293 if (err_fns) return; | |
294 | |
295 CRYPTO_w_lock(CRYPTO_LOCK_ERR); | |
296 if (!err_fns) | |
297 err_fns = &err_defaults; | |
298 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); | |
299 } | |
300 | |
301 /* API functions to get or set the underlying ERR functions. */ | |
302 | |
303 const ERR_FNS *ERR_get_implementation(void) | |
304 { | |
305 err_fns_check(); | |
306 return err_fns; | |
307 } | |
308 | |
309 int ERR_set_implementation(const ERR_FNS *fns) | |
310 { | |
311 int ret = 0; | |
312 | |
313 CRYPTO_w_lock(CRYPTO_LOCK_ERR); | |
314 /* It's too late if 'err_fns' is non-NULL. BTW: not much point setting | |
315 * an error is there?! */ | |
316 if (!err_fns) | |
317 { | |
318 err_fns = fns; | |
319 ret = 1; | |
320 } | |
321 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); | |
322 return ret; | |
323 } | |
324 | |
325 /* These are the callbacks provided to "lh_new()" when creating the LHASH tables | |
326 * internal to the "err_defaults" implementation. */ | |
327 | |
328 static unsigned long get_error_values(int inc,int top,const char **file,int *lin
e, | |
329 const char **data,int *flags); | |
330 | |
331 /* The internal functions used in the "err_defaults" implementation */ | |
332 | |
333 static unsigned long err_string_data_hash(const ERR_STRING_DATA *a) | |
334 { | |
335 unsigned long ret,l; | |
336 | |
337 l=a->error; | |
338 ret=l^ERR_GET_LIB(l)^ERR_GET_FUNC(l); | |
339 return(ret^ret%19*13); | |
340 } | |
341 static IMPLEMENT_LHASH_HASH_FN(err_string_data, ERR_STRING_DATA) | |
342 | |
343 static int err_string_data_cmp(const ERR_STRING_DATA *a, | |
344 const ERR_STRING_DATA *b) | |
345 { | |
346 return (int)(a->error - b->error); | |
347 } | |
348 static IMPLEMENT_LHASH_COMP_FN(err_string_data, ERR_STRING_DATA) | |
349 | |
350 static LHASH_OF(ERR_STRING_DATA) *int_err_get(int create) | |
351 { | |
352 LHASH_OF(ERR_STRING_DATA) *ret = NULL; | |
353 | |
354 CRYPTO_w_lock(CRYPTO_LOCK_ERR); | |
355 if (!int_error_hash && create) | |
356 { | |
357 CRYPTO_push_info("int_err_get (err.c)"); | |
358 int_error_hash = lh_ERR_STRING_DATA_new(); | |
359 CRYPTO_pop_info(); | |
360 } | |
361 if (int_error_hash) | |
362 ret = int_error_hash; | |
363 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); | |
364 | |
365 return ret; | |
366 } | |
367 | |
368 static void int_err_del(void) | |
369 { | |
370 CRYPTO_w_lock(CRYPTO_LOCK_ERR); | |
371 if (int_error_hash) | |
372 { | |
373 lh_ERR_STRING_DATA_free(int_error_hash); | |
374 int_error_hash = NULL; | |
375 } | |
376 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); | |
377 } | |
378 | |
379 static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *d) | |
380 { | |
381 ERR_STRING_DATA *p; | |
382 LHASH_OF(ERR_STRING_DATA) *hash; | |
383 | |
384 err_fns_check(); | |
385 hash = ERRFN(err_get)(0); | |
386 if (!hash) | |
387 return NULL; | |
388 | |
389 CRYPTO_r_lock(CRYPTO_LOCK_ERR); | |
390 p = lh_ERR_STRING_DATA_retrieve(hash, d); | |
391 CRYPTO_r_unlock(CRYPTO_LOCK_ERR); | |
392 | |
393 return p; | |
394 } | |
395 | |
396 static ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *d) | |
397 { | |
398 ERR_STRING_DATA *p; | |
399 LHASH_OF(ERR_STRING_DATA) *hash; | |
400 | |
401 err_fns_check(); | |
402 hash = ERRFN(err_get)(1); | |
403 if (!hash) | |
404 return NULL; | |
405 | |
406 CRYPTO_w_lock(CRYPTO_LOCK_ERR); | |
407 p = lh_ERR_STRING_DATA_insert(hash, d); | |
408 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); | |
409 | |
410 return p; | |
411 } | |
412 | |
413 static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *d) | |
414 { | |
415 ERR_STRING_DATA *p; | |
416 LHASH_OF(ERR_STRING_DATA) *hash; | |
417 | |
418 err_fns_check(); | |
419 hash = ERRFN(err_get)(0); | |
420 if (!hash) | |
421 return NULL; | |
422 | |
423 CRYPTO_w_lock(CRYPTO_LOCK_ERR); | |
424 p = lh_ERR_STRING_DATA_delete(hash, d); | |
425 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); | |
426 | |
427 return p; | |
428 } | |
429 | |
430 static unsigned long err_state_hash(const ERR_STATE *a) | |
431 { | |
432 return CRYPTO_THREADID_hash(&a->tid) * 13; | |
433 } | |
434 static IMPLEMENT_LHASH_HASH_FN(err_state, ERR_STATE) | |
435 | |
436 static int err_state_cmp(const ERR_STATE *a, const ERR_STATE *b) | |
437 { | |
438 return CRYPTO_THREADID_cmp(&a->tid, &b->tid); | |
439 } | |
440 static IMPLEMENT_LHASH_COMP_FN(err_state, ERR_STATE) | |
441 | |
442 static LHASH_OF(ERR_STATE) *int_thread_get(int create) | |
443 { | |
444 LHASH_OF(ERR_STATE) *ret = NULL; | |
445 | |
446 CRYPTO_w_lock(CRYPTO_LOCK_ERR); | |
447 if (!int_thread_hash && create) | |
448 { | |
449 CRYPTO_push_info("int_thread_get (err.c)"); | |
450 int_thread_hash = lh_ERR_STATE_new(); | |
451 CRYPTO_pop_info(); | |
452 } | |
453 if (int_thread_hash) | |
454 { | |
455 int_thread_hash_references++; | |
456 ret = int_thread_hash; | |
457 } | |
458 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); | |
459 return ret; | |
460 } | |
461 | |
462 static void int_thread_release(LHASH_OF(ERR_STATE) **hash) | |
463 { | |
464 int i; | |
465 | |
466 if (hash == NULL || *hash == NULL) | |
467 return; | |
468 | |
469 i = CRYPTO_add(&int_thread_hash_references, -1, CRYPTO_LOCK_ERR); | |
470 | |
471 #ifdef REF_PRINT | |
472 fprintf(stderr,"%4d:%s\n",int_thread_hash_references,"ERR"); | |
473 #endif | |
474 if (i > 0) return; | |
475 #ifdef REF_CHECK | |
476 if (i < 0) | |
477 { | |
478 fprintf(stderr,"int_thread_release, bad reference count\n"); | |
479 abort(); /* ok */ | |
480 } | |
481 #endif | |
482 *hash = NULL; | |
483 } | |
484 | |
485 static ERR_STATE *int_thread_get_item(const ERR_STATE *d) | |
486 { | |
487 ERR_STATE *p; | |
488 LHASH_OF(ERR_STATE) *hash; | |
489 | |
490 err_fns_check(); | |
491 hash = ERRFN(thread_get)(0); | |
492 if (!hash) | |
493 return NULL; | |
494 | |
495 CRYPTO_r_lock(CRYPTO_LOCK_ERR); | |
496 p = lh_ERR_STATE_retrieve(hash, d); | |
497 CRYPTO_r_unlock(CRYPTO_LOCK_ERR); | |
498 | |
499 ERRFN(thread_release)(&hash); | |
500 return p; | |
501 } | |
502 | |
503 static ERR_STATE *int_thread_set_item(ERR_STATE *d) | |
504 { | |
505 ERR_STATE *p; | |
506 LHASH_OF(ERR_STATE) *hash; | |
507 | |
508 err_fns_check(); | |
509 hash = ERRFN(thread_get)(1); | |
510 if (!hash) | |
511 return NULL; | |
512 | |
513 CRYPTO_w_lock(CRYPTO_LOCK_ERR); | |
514 p = lh_ERR_STATE_insert(hash, d); | |
515 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); | |
516 | |
517 ERRFN(thread_release)(&hash); | |
518 return p; | |
519 } | |
520 | |
521 static void int_thread_del_item(const ERR_STATE *d) | |
522 { | |
523 ERR_STATE *p; | |
524 LHASH_OF(ERR_STATE) *hash; | |
525 | |
526 err_fns_check(); | |
527 hash = ERRFN(thread_get)(0); | |
528 if (!hash) | |
529 return; | |
530 | |
531 CRYPTO_w_lock(CRYPTO_LOCK_ERR); | |
532 p = lh_ERR_STATE_delete(hash, d); | |
533 /* make sure we don't leak memory */ | |
534 if (int_thread_hash_references == 1 | |
535 && int_thread_hash && lh_ERR_STATE_num_items(int_thread_hash) == 0) | |
536 { | |
537 lh_ERR_STATE_free(int_thread_hash); | |
538 int_thread_hash = NULL; | |
539 } | |
540 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); | |
541 | |
542 ERRFN(thread_release)(&hash); | |
543 if (p) | |
544 ERR_STATE_free(p); | |
545 } | |
546 | |
547 static int int_err_get_next_lib(void) | |
548 { | |
549 int ret; | |
550 | |
551 CRYPTO_w_lock(CRYPTO_LOCK_ERR); | |
552 ret = int_err_library_number++; | |
553 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); | |
554 | |
555 return ret; | |
556 } | |
557 | |
558 | |
559 #ifndef OPENSSL_NO_ERR | |
560 #define NUM_SYS_STR_REASONS 127 | |
561 #define LEN_SYS_STR_REASON 32 | |
562 | |
563 static ERR_STRING_DATA SYS_str_reasons[NUM_SYS_STR_REASONS + 1]; | |
564 /* SYS_str_reasons is filled with copies of strerror() results at | |
565 * initialization. | |
566 * 'errno' values up to 127 should cover all usual errors, | |
567 * others will be displayed numerically by ERR_error_string. | |
568 * It is crucial that we have something for each reason code | |
569 * that occurs in ERR_str_reasons, or bogus reason strings | |
570 * will be returned for SYSerr(), which always gets an errno | |
571 * value and never one of those 'standard' reason codes. */ | |
572 | |
573 static void build_SYS_str_reasons(void) | |
574 { | |
575 /* OPENSSL_malloc cannot be used here, use static storage instead */ | |
576 static char strerror_tab[NUM_SYS_STR_REASONS][LEN_SYS_STR_REASON]; | |
577 int i; | |
578 static int init = 1; | |
579 | |
580 CRYPTO_r_lock(CRYPTO_LOCK_ERR); | |
581 if (!init) | |
582 { | |
583 CRYPTO_r_unlock(CRYPTO_LOCK_ERR); | |
584 return; | |
585 } | |
586 | |
587 CRYPTO_r_unlock(CRYPTO_LOCK_ERR); | |
588 CRYPTO_w_lock(CRYPTO_LOCK_ERR); | |
589 if (!init) | |
590 { | |
591 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); | |
592 return; | |
593 } | |
594 | |
595 for (i = 1; i <= NUM_SYS_STR_REASONS; i++) | |
596 { | |
597 ERR_STRING_DATA *str = &SYS_str_reasons[i - 1]; | |
598 | |
599 str->error = (unsigned long)i; | |
600 if (str->string == NULL) | |
601 { | |
602 char (*dest)[LEN_SYS_STR_REASON] = &(strerror_tab[i - 1]
); | |
603 char *src = strerror(i); | |
604 if (src != NULL) | |
605 { | |
606 strncpy(*dest, src, sizeof *dest); | |
607 (*dest)[sizeof *dest - 1] = '\0'; | |
608 str->string = *dest; | |
609 } | |
610 } | |
611 if (str->string == NULL) | |
612 str->string = "unknown"; | |
613 } | |
614 | |
615 /* Now we still have SYS_str_reasons[NUM_SYS_STR_REASONS] = {0, NULL}, | |
616 * as required by ERR_load_strings. */ | |
617 | |
618 init = 0; | |
619 | |
620 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); | |
621 } | |
622 #endif | |
623 | |
624 #define err_clear_data(p,i) \ | |
625 do { \ | |
626 if (((p)->err_data[i] != NULL) && \ | |
627 (p)->err_data_flags[i] & ERR_TXT_MALLOCED) \ | |
628 { \ | |
629 OPENSSL_free((p)->err_data[i]); \ | |
630 (p)->err_data[i]=NULL; \ | |
631 } \ | |
632 (p)->err_data_flags[i]=0; \ | |
633 } while(0) | |
634 | |
635 #define err_clear(p,i) \ | |
636 do { \ | |
637 (p)->err_flags[i]=0; \ | |
638 (p)->err_buffer[i]=0; \ | |
639 err_clear_data(p,i); \ | |
640 (p)->err_file[i]=NULL; \ | |
641 (p)->err_line[i]= -1; \ | |
642 } while(0) | |
643 | |
644 static void ERR_STATE_free(ERR_STATE *s) | |
645 { | |
646 int i; | |
647 | |
648 if (s == NULL) | |
649 return; | |
650 | |
651 for (i=0; i<ERR_NUM_ERRORS; i++) | |
652 { | |
653 err_clear_data(s,i); | |
654 } | |
655 OPENSSL_free(s); | |
656 } | |
657 | |
658 void ERR_load_ERR_strings(void) | |
659 { | |
660 err_fns_check(); | |
661 #ifndef OPENSSL_NO_ERR | |
662 err_load_strings(0,ERR_str_libraries); | |
663 err_load_strings(0,ERR_str_reasons); | |
664 err_load_strings(ERR_LIB_SYS,ERR_str_functs); | |
665 build_SYS_str_reasons(); | |
666 err_load_strings(ERR_LIB_SYS,SYS_str_reasons); | |
667 #endif | |
668 } | |
669 | |
670 static void err_load_strings(int lib, ERR_STRING_DATA *str) | |
671 { | |
672 while (str->error) | |
673 { | |
674 if (lib) | |
675 str->error|=ERR_PACK(lib,0,0); | |
676 ERRFN(err_set_item)(str); | |
677 str++; | |
678 } | |
679 } | |
680 | |
681 void ERR_load_strings(int lib, ERR_STRING_DATA *str) | |
682 { | |
683 ERR_load_ERR_strings(); | |
684 err_load_strings(lib, str); | |
685 } | |
686 | |
687 void ERR_unload_strings(int lib, ERR_STRING_DATA *str) | |
688 { | |
689 while (str->error) | |
690 { | |
691 if (lib) | |
692 str->error|=ERR_PACK(lib,0,0); | |
693 ERRFN(err_del_item)(str); | |
694 str++; | |
695 } | |
696 } | |
697 | |
698 void ERR_free_strings(void) | |
699 { | |
700 err_fns_check(); | |
701 ERRFN(err_del)(); | |
702 } | |
703 | |
704 /********************************************************/ | |
705 | |
706 void ERR_put_error(int lib, int func, int reason, const char *file, | |
707 int line) | |
708 { | |
709 ERR_STATE *es; | |
710 | |
711 #ifdef _OSD_POSIX | |
712 /* In the BS2000-OSD POSIX subsystem, the compiler generates | |
713 * path names in the form "*POSIX(/etc/passwd)". | |
714 * This dirty hack strips them to something sensible. | |
715 * @@@ We shouldn't modify a const string, though. | |
716 */ | |
717 if (strncmp(file,"*POSIX(", sizeof("*POSIX(")-1) == 0) { | |
718 char *end; | |
719 | |
720 /* Skip the "*POSIX(" prefix */ | |
721 file += sizeof("*POSIX(")-1; | |
722 end = &file[strlen(file)-1]; | |
723 if (*end == ')') | |
724 *end = '\0'; | |
725 /* Optional: use the basename of the path only. */ | |
726 if ((end = strrchr(file, '/')) != NULL) | |
727 file = &end[1]; | |
728 } | |
729 #endif | |
730 es=ERR_get_state(); | |
731 | |
732 es->top=(es->top+1)%ERR_NUM_ERRORS; | |
733 if (es->top == es->bottom) | |
734 es->bottom=(es->bottom+1)%ERR_NUM_ERRORS; | |
735 es->err_flags[es->top]=0; | |
736 es->err_buffer[es->top]=ERR_PACK(lib,func,reason); | |
737 es->err_file[es->top]=file; | |
738 es->err_line[es->top]=line; | |
739 err_clear_data(es,es->top); | |
740 } | |
741 | |
742 void ERR_clear_error(void) | |
743 { | |
744 int i; | |
745 ERR_STATE *es; | |
746 | |
747 es=ERR_get_state(); | |
748 | |
749 for (i=0; i<ERR_NUM_ERRORS; i++) | |
750 { | |
751 err_clear(es,i); | |
752 } | |
753 es->top=es->bottom=0; | |
754 } | |
755 | |
756 | |
757 unsigned long ERR_get_error(void) | |
758 { return(get_error_values(1,0,NULL,NULL,NULL,NULL)); } | |
759 | |
760 unsigned long ERR_get_error_line(const char **file, | |
761 int *line) | |
762 { return(get_error_values(1,0,file,line,NULL,NULL)); } | |
763 | |
764 unsigned long ERR_get_error_line_data(const char **file, int *line, | |
765 const char **data, int *flags) | |
766 { return(get_error_values(1,0,file,line,data,flags)); } | |
767 | |
768 | |
769 unsigned long ERR_peek_error(void) | |
770 { return(get_error_values(0,0,NULL,NULL,NULL,NULL)); } | |
771 | |
772 unsigned long ERR_peek_error_line(const char **file, int *line) | |
773 { return(get_error_values(0,0,file,line,NULL,NULL)); } | |
774 | |
775 unsigned long ERR_peek_error_line_data(const char **file, int *line, | |
776 const char **data, int *flags) | |
777 { return(get_error_values(0,0,file,line,data,flags)); } | |
778 | |
779 | |
780 unsigned long ERR_peek_last_error(void) | |
781 { return(get_error_values(0,1,NULL,NULL,NULL,NULL)); } | |
782 | |
783 unsigned long ERR_peek_last_error_line(const char **file, int *line) | |
784 { return(get_error_values(0,1,file,line,NULL,NULL)); } | |
785 | |
786 unsigned long ERR_peek_last_error_line_data(const char **file, int *line, | |
787 const char **data, int *flags) | |
788 { return(get_error_values(0,1,file,line,data,flags)); } | |
789 | |
790 | |
791 static unsigned long get_error_values(int inc, int top, const char **file, int *
line, | |
792 const char **data, int *flags) | |
793 { | |
794 int i=0; | |
795 ERR_STATE *es; | |
796 unsigned long ret; | |
797 | |
798 es=ERR_get_state(); | |
799 | |
800 if (inc && top) | |
801 { | |
802 if (file) *file = ""; | |
803 if (line) *line = 0; | |
804 if (data) *data = ""; | |
805 if (flags) *flags = 0; | |
806 | |
807 return ERR_R_INTERNAL_ERROR; | |
808 } | |
809 | |
810 if (es->bottom == es->top) return 0; | |
811 if (top) | |
812 i=es->top; /* last error */ | |
813 else | |
814 i=(es->bottom+1)%ERR_NUM_ERRORS; /* first error */ | |
815 | |
816 ret=es->err_buffer[i]; | |
817 if (inc) | |
818 { | |
819 es->bottom=i; | |
820 es->err_buffer[i]=0; | |
821 } | |
822 | |
823 if ((file != NULL) && (line != NULL)) | |
824 { | |
825 if (es->err_file[i] == NULL) | |
826 { | |
827 *file="NA"; | |
828 if (line != NULL) *line=0; | |
829 } | |
830 else | |
831 { | |
832 *file=es->err_file[i]; | |
833 if (line != NULL) *line=es->err_line[i]; | |
834 } | |
835 } | |
836 | |
837 if (data == NULL) | |
838 { | |
839 if (inc) | |
840 { | |
841 err_clear_data(es, i); | |
842 } | |
843 } | |
844 else | |
845 { | |
846 if (es->err_data[i] == NULL) | |
847 { | |
848 *data=""; | |
849 if (flags != NULL) *flags=0; | |
850 } | |
851 else | |
852 { | |
853 *data=es->err_data[i]; | |
854 if (flags != NULL) *flags=es->err_data_flags[i]; | |
855 } | |
856 } | |
857 return ret; | |
858 } | |
859 | |
860 void ERR_error_string_n(unsigned long e, char *buf, size_t len) | |
861 { | |
862 char lsbuf[64], fsbuf[64], rsbuf[64]; | |
863 const char *ls,*fs,*rs; | |
864 unsigned long l,f,r; | |
865 | |
866 l=ERR_GET_LIB(e); | |
867 f=ERR_GET_FUNC(e); | |
868 r=ERR_GET_REASON(e); | |
869 | |
870 ls=ERR_lib_error_string(e); | |
871 fs=ERR_func_error_string(e); | |
872 rs=ERR_reason_error_string(e); | |
873 | |
874 if (ls == NULL) | |
875 BIO_snprintf(lsbuf, sizeof(lsbuf), "lib(%lu)", l); | |
876 if (fs == NULL) | |
877 BIO_snprintf(fsbuf, sizeof(fsbuf), "func(%lu)", f); | |
878 if (rs == NULL) | |
879 BIO_snprintf(rsbuf, sizeof(rsbuf), "reason(%lu)", r); | |
880 | |
881 BIO_snprintf(buf, len,"error:%08lX:%s:%s:%s", e, ls?ls:lsbuf, | |
882 fs?fs:fsbuf, rs?rs:rsbuf); | |
883 if (strlen(buf) == len-1) | |
884 { | |
885 /* output may be truncated; make sure we always have 5 | |
886 * colon-separated fields, i.e. 4 colons ... */ | |
887 #define NUM_COLONS 4 | |
888 if (len > NUM_COLONS) /* ... if possible */ | |
889 { | |
890 int i; | |
891 char *s = buf; | |
892 | |
893 for (i = 0; i < NUM_COLONS; i++) | |
894 { | |
895 char *colon = strchr(s, ':'); | |
896 if (colon == NULL || colon > &buf[len-1] - NUM_C
OLONS + i) | |
897 { | |
898 /* set colon no. i at last possible posi
tion | |
899 * (buf[len-1] is the terminating 0)*/ | |
900 colon = &buf[len-1] - NUM_COLONS + i; | |
901 *colon = ':'; | |
902 } | |
903 s = colon + 1; | |
904 } | |
905 } | |
906 } | |
907 } | |
908 | |
909 /* BAD for multi-threading: uses a local buffer if ret == NULL */ | |
910 /* ERR_error_string_n should be used instead for ret != NULL | |
911 * as ERR_error_string cannot know how large the buffer is */ | |
912 char *ERR_error_string(unsigned long e, char *ret) | |
913 { | |
914 static char buf[256]; | |
915 | |
916 if (ret == NULL) ret=buf; | |
917 ERR_error_string_n(e, ret, 256); | |
918 | |
919 return ret; | |
920 } | |
921 | |
922 LHASH_OF(ERR_STRING_DATA) *ERR_get_string_table(void) | |
923 { | |
924 err_fns_check(); | |
925 return ERRFN(err_get)(0); | |
926 } | |
927 | |
928 LHASH_OF(ERR_STATE) *ERR_get_err_state_table(void) | |
929 { | |
930 err_fns_check(); | |
931 return ERRFN(thread_get)(0); | |
932 } | |
933 | |
934 void ERR_release_err_state_table(LHASH_OF(ERR_STATE) **hash) | |
935 { | |
936 err_fns_check(); | |
937 ERRFN(thread_release)(hash); | |
938 } | |
939 | |
940 const char *ERR_lib_error_string(unsigned long e) | |
941 { | |
942 ERR_STRING_DATA d,*p; | |
943 unsigned long l; | |
944 | |
945 err_fns_check(); | |
946 l=ERR_GET_LIB(e); | |
947 d.error=ERR_PACK(l,0,0); | |
948 p=ERRFN(err_get_item)(&d); | |
949 return((p == NULL)?NULL:p->string); | |
950 } | |
951 | |
952 const char *ERR_func_error_string(unsigned long e) | |
953 { | |
954 ERR_STRING_DATA d,*p; | |
955 unsigned long l,f; | |
956 | |
957 err_fns_check(); | |
958 l=ERR_GET_LIB(e); | |
959 f=ERR_GET_FUNC(e); | |
960 d.error=ERR_PACK(l,f,0); | |
961 p=ERRFN(err_get_item)(&d); | |
962 return((p == NULL)?NULL:p->string); | |
963 } | |
964 | |
965 const char *ERR_reason_error_string(unsigned long e) | |
966 { | |
967 ERR_STRING_DATA d,*p=NULL; | |
968 unsigned long l,r; | |
969 | |
970 err_fns_check(); | |
971 l=ERR_GET_LIB(e); | |
972 r=ERR_GET_REASON(e); | |
973 d.error=ERR_PACK(l,0,r); | |
974 p=ERRFN(err_get_item)(&d); | |
975 if (!p) | |
976 { | |
977 d.error=ERR_PACK(0,0,r); | |
978 p=ERRFN(err_get_item)(&d); | |
979 } | |
980 return((p == NULL)?NULL:p->string); | |
981 } | |
982 | |
983 void ERR_remove_thread_state(const CRYPTO_THREADID *id) | |
984 { | |
985 ERR_STATE tmp; | |
986 | |
987 if (id) | |
988 CRYPTO_THREADID_cpy(&tmp.tid, id); | |
989 else | |
990 CRYPTO_THREADID_current(&tmp.tid); | |
991 err_fns_check(); | |
992 /* thread_del_item automatically destroys the LHASH if the number of | |
993 * items reaches zero. */ | |
994 ERRFN(thread_del_item)(&tmp); | |
995 } | |
996 | |
997 #ifndef OPENSSL_NO_DEPRECATED | |
998 void ERR_remove_state(unsigned long pid) | |
999 { | |
1000 ERR_remove_thread_state(NULL); | |
1001 } | |
1002 #endif | |
1003 | |
1004 ERR_STATE *ERR_get_state(void) | |
1005 { | |
1006 static ERR_STATE fallback; | |
1007 ERR_STATE *ret,tmp,*tmpp=NULL; | |
1008 int i; | |
1009 CRYPTO_THREADID tid; | |
1010 | |
1011 err_fns_check(); | |
1012 CRYPTO_THREADID_current(&tid); | |
1013 CRYPTO_THREADID_cpy(&tmp.tid, &tid); | |
1014 ret=ERRFN(thread_get_item)(&tmp); | |
1015 | |
1016 /* ret == the error state, if NULL, make a new one */ | |
1017 if (ret == NULL) | |
1018 { | |
1019 ret=(ERR_STATE *)OPENSSL_malloc(sizeof(ERR_STATE)); | |
1020 if (ret == NULL) return(&fallback); | |
1021 CRYPTO_THREADID_cpy(&ret->tid, &tid); | |
1022 ret->top=0; | |
1023 ret->bottom=0; | |
1024 for (i=0; i<ERR_NUM_ERRORS; i++) | |
1025 { | |
1026 ret->err_data[i]=NULL; | |
1027 ret->err_data_flags[i]=0; | |
1028 } | |
1029 tmpp = ERRFN(thread_set_item)(ret); | |
1030 /* To check if insertion failed, do a get. */ | |
1031 if (ERRFN(thread_get_item)(ret) != ret) | |
1032 { | |
1033 ERR_STATE_free(ret); /* could not insert it */ | |
1034 return(&fallback); | |
1035 } | |
1036 /* If a race occured in this function and we came second, tmpp | |
1037 * is the first one that we just replaced. */ | |
1038 if (tmpp) | |
1039 ERR_STATE_free(tmpp); | |
1040 } | |
1041 return ret; | |
1042 } | |
1043 | |
1044 int ERR_get_next_error_library(void) | |
1045 { | |
1046 err_fns_check(); | |
1047 return ERRFN(get_next_lib)(); | |
1048 } | |
1049 | |
1050 void ERR_set_error_data(char *data, int flags) | |
1051 { | |
1052 ERR_STATE *es; | |
1053 int i; | |
1054 | |
1055 es=ERR_get_state(); | |
1056 | |
1057 i=es->top; | |
1058 if (i == 0) | |
1059 i=ERR_NUM_ERRORS-1; | |
1060 | |
1061 err_clear_data(es,i); | |
1062 es->err_data[i]=data; | |
1063 es->err_data_flags[i]=flags; | |
1064 } | |
1065 | |
1066 void ERR_add_error_data(int num, ...) | |
1067 { | |
1068 va_list args; | |
1069 va_start(args, num); | |
1070 ERR_add_error_vdata(num, args); | |
1071 va_end(args); | |
1072 } | |
1073 | |
1074 void ERR_add_error_vdata(int num, va_list args) | |
1075 { | |
1076 int i,n,s; | |
1077 char *str,*p,*a; | |
1078 | |
1079 s=80; | |
1080 str=OPENSSL_malloc(s+1); | |
1081 if (str == NULL) return; | |
1082 str[0]='\0'; | |
1083 | |
1084 n=0; | |
1085 for (i=0; i<num; i++) | |
1086 { | |
1087 a=va_arg(args, char*); | |
1088 /* ignore NULLs, thanks to Bob Beck <beck@obtuse.com> */ | |
1089 if (a != NULL) | |
1090 { | |
1091 n+=strlen(a); | |
1092 if (n > s) | |
1093 { | |
1094 s=n+20; | |
1095 p=OPENSSL_realloc(str,s+1); | |
1096 if (p == NULL) | |
1097 { | |
1098 OPENSSL_free(str); | |
1099 return; | |
1100 } | |
1101 else | |
1102 str=p; | |
1103 } | |
1104 BUF_strlcat(str,a,(size_t)s+1); | |
1105 } | |
1106 } | |
1107 ERR_set_error_data(str,ERR_TXT_MALLOCED|ERR_TXT_STRING); | |
1108 } | |
1109 | |
1110 int ERR_set_mark(void) | |
1111 { | |
1112 ERR_STATE *es; | |
1113 | |
1114 es=ERR_get_state(); | |
1115 | |
1116 if (es->bottom == es->top) return 0; | |
1117 es->err_flags[es->top]|=ERR_FLAG_MARK; | |
1118 return 1; | |
1119 } | |
1120 | |
1121 int ERR_pop_to_mark(void) | |
1122 { | |
1123 ERR_STATE *es; | |
1124 | |
1125 es=ERR_get_state(); | |
1126 | |
1127 while(es->bottom != es->top | |
1128 && (es->err_flags[es->top] & ERR_FLAG_MARK) == 0) | |
1129 { | |
1130 err_clear(es,es->top); | |
1131 es->top-=1; | |
1132 if (es->top == -1) es->top=ERR_NUM_ERRORS-1; | |
1133 } | |
1134 | |
1135 if (es->bottom == es->top) return 0; | |
1136 es->err_flags[es->top]&=~ERR_FLAG_MARK; | |
1137 return 1; | |
1138 } | |
OLD | NEW |