1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF5. The full HDF5 copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the COPYING file, which can be found at the root of the source code *
9 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 /*-------------------------------------------------------------------------
15 *
16 * Created: H5Eint.c
17 * April 11 2007
18 * Quincey Koziol <koziol@hdfgroup.org>
19 *
20 * Purpose: General use, "internal" routines for error handling.
21 *
22 *-------------------------------------------------------------------------
23 */
24
25 /****************/
26 /* Module Setup */
27 /****************/
28
29 #define H5E_PACKAGE /*suppress error about including H5Epkg */
30
31 /* Interface initialization */
32 #define H5_INTERFACE_INIT_FUNC H5E_init_int_interface
33
34
35 /***********/
36 /* Headers */
37 /***********/
38 #include "H5private.h" /* Generic Functions */
39 #include "H5Epkg.h" /* Error handling */
40 #include "H5Iprivate.h" /* IDs */
41 #include "H5MMprivate.h" /* Memory management */
42
43
44 /****************/
45 /* Local Macros */
46 /****************/
47
48
49 /******************/
50 /* Local Typedefs */
51 /******************/
52
53 /* Printing information */
54 typedef struct H5E_print_t {
55 FILE *stream;
56 H5E_cls_t cls;
57 } H5E_print_t;
58
59
60 /********************/
61 /* Package Typedefs */
62 /********************/
63
64
65 /********************/
66 /* Local Prototypes */
67 /********************/
68 #ifndef H5_NO_DEPRECATED_SYMBOLS
69 static herr_t H5E_walk1_cb(int n, H5E_error1_t *err_desc,
70 void *client_data);
71 #endif /* H5_NO_DEPRECATED_SYMBOLS */
72 static herr_t H5E_walk2_cb(unsigned n, const H5E_error2_t *err_desc,
73 void *client_data);
74 static herr_t H5E_clear_entries(H5E_t *estack, size_t nentries);
75
76
77 /*********************/
78 /* Package Variables */
79 /*********************/
80
81 #ifndef H5_HAVE_THREADSAFE
82 /*
83 * The current error stack.
84 */
85 H5E_t H5E_stack_g[1];
86 #endif /* H5_HAVE_THREADSAFE */
87
88
89 /*****************************/
90 /* Library Private Variables */
91 /*****************************/
92
93 /* HDF5 error class ID */
94 hid_t H5E_ERR_CLS_g = FAIL;
95
96 /*
97 * Predefined errors. These are initialized at runtime in H5E_init_interface()
98 * in this source file.
99 */
100 /* Include the automatically generated error code definitions */
101 #include "H5Edefin.h"
102
103
104 /*******************/
105 /* Local Variables */
106 /*******************/
107
108 #ifdef H5_HAVE_PARALLEL
109 /*
110 * variables used for MPI error reporting
111 */
112 char H5E_mpi_error_str[MPI_MAX_ERROR_STRING];
113 int H5E_mpi_error_str_len;
114 #endif /* H5_HAVE_PARALLEL */
115
116
117
118 /*--------------------------------------------------------------------------
119 NAME
120 H5E_init_int_interface -- Initialize interface-specific information
121 USAGE
122 herr_t H5E_init_int_interface()
123 RETURNS
124 Non-negative on success/Negative on failure
125 DESCRIPTION
126 Initializes any interface-specific data or routines. (Just calls
127 H5E_init() currently).
128
129 --------------------------------------------------------------------------*/
130 static herr_t
H5E_init_int_interface(void)131 H5E_init_int_interface(void)
132 {
133 FUNC_ENTER_NOAPI_NOINIT_NOERR
134
135 FUNC_LEAVE_NOAPI(H5E_init())
136 } /* H5E_init_int_interface() */
137
138
139 /*-------------------------------------------------------------------------
140 * Function: H5E_get_msg
141 *
142 * Purpose: Private function to retrieve an error message.
143 *
144 * Return: Non-negative for name length if succeeds(zero means no name);
145 * otherwise returns negative value.
146 *
147 * Programmer: Raymond Lu
148 * Friday, July 14, 2003
149 *
150 *-------------------------------------------------------------------------
151 */
152 ssize_t
H5E_get_msg(const H5E_msg_t * msg,H5E_type_t * type,char * msg_str,size_t size)153 H5E_get_msg(const H5E_msg_t *msg, H5E_type_t *type, char *msg_str, size_t size)
154 {
155 ssize_t len; /* Length of error message */
156
157 FUNC_ENTER_NOAPI_NOINIT_NOERR
158
159 /* Check arguments */
160 HDassert(msg);
161
162 /* Get the length of the message string */
163 len = (ssize_t)HDstrlen(msg->msg);
164
165 /* Copy the message into the user's buffer, if given */
166 if(msg_str) {
167 HDstrncpy(msg_str, msg->msg, MIN((size_t)(len+1), size));
168 if((size_t)len >= size)
169 msg_str[size - 1] = '\0';
170 } /* end if */
171
172 /* Give the message type, if asked */
173 if(type)
174 *type = msg->type;
175
176 /* Set the return value to the full length of the message */
177 FUNC_LEAVE_NOAPI(len)
178 } /* end H5E_get_msg() */
179
180 #ifndef H5_NO_DEPRECATED_SYMBOLS
181
182 /*-------------------------------------------------------------------------
183 * Function: H5E_walk1_cb
184 *
185 * Purpose: This function is for backward compatibility.
186 * This is a default error stack traversal callback function
187 * that prints error messages to the specified output stream.
188 * This function is for backward compatibility with v1.6.
189 * It is not meant to be called directly but rather as an
190 * argument to the H5Ewalk() function. This function is called
191 * also by H5Eprint(). Application writers are encouraged to
192 * use this function as a model for their own error stack
193 * walking functions.
194 *
195 * N is a counter for how many times this function has been
196 * called for this particular traversal of the stack. It always
197 * begins at zero for the first error on the stack (either the
198 * top or bottom error, or even both, depending on the traversal
199 * direction and the size of the stack).
200 *
201 * ERR_DESC is an error description. It contains all the
202 * information about a particular error.
203 *
204 * CLIENT_DATA is the same pointer that was passed as the
205 * CLIENT_DATA argument of H5Ewalk(). It is expected to be a
206 * file pointer (or stderr if null).
207 *
208 * Return: Non-negative on success/Negative on failure
209 *
210 * Programmer: Raymond Lu
211 * Thursday, May 11, 2006
212 *
213 *-------------------------------------------------------------------------
214 */
215 static herr_t
H5E_walk1_cb(int n,H5E_error1_t * err_desc,void * client_data)216 H5E_walk1_cb(int n, H5E_error1_t *err_desc, void *client_data)
217 {
218 H5E_print_t *eprint = (H5E_print_t *)client_data;
219 FILE *stream; /* I/O stream to print output to */
220 H5E_cls_t *cls_ptr; /* Pointer to error class */
221 H5E_msg_t *maj_ptr; /* Pointer to major error info */
222 H5E_msg_t *min_ptr; /* Pointer to minor error info */
223 const char *maj_str = "No major description"; /* Major error description */
224 const char *min_str = "No minor description"; /* Minor error description */
225 unsigned have_desc = 1; /* Flag to indicate whether the error has a "real" description */
226 herr_t ret_value = SUCCEED;
227
228 FUNC_ENTER_NOAPI_NOINIT_NOERR
229
230 /* Check arguments */
231 HDassert(err_desc);
232
233 /* If no client data was passed, output to stderr */
234 if(!client_data)
235 stream = stderr;
236 else
237 stream = eprint->stream;
238
239 /* Get descriptions for the major and minor error numbers */
240 maj_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->maj_num, H5I_ERROR_MSG);
241 min_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->min_num, H5I_ERROR_MSG);
242
243 /* Check for bad pointer(s), but can't issue error, just leave */
244 if(!maj_ptr || !min_ptr)
245 HGOTO_DONE(FAIL)
246
247 if(maj_ptr->msg)
248 maj_str = maj_ptr->msg;
249 if(min_ptr->msg)
250 min_str = min_ptr->msg;
251
252 /* Get error class info */
253 cls_ptr = maj_ptr->cls;
254
255 /* Print error class header if new class */
256 if(eprint->cls.lib_name == NULL || HDstrcmp(cls_ptr->lib_name, eprint->cls.lib_name)) {
257 /* update to the new class information */
258 if(cls_ptr->cls_name)
259 eprint->cls.cls_name = cls_ptr->cls_name;
260 if(cls_ptr->lib_name)
261 eprint->cls.lib_name = cls_ptr->lib_name;
262 if(cls_ptr->lib_vers)
263 eprint->cls.lib_vers = cls_ptr->lib_vers;
264
265 fprintf(stream, "%s-DIAG: Error detected in %s (%s) ",
266 (cls_ptr->cls_name ? cls_ptr->cls_name : "(null)"),
267 (cls_ptr->lib_name ? cls_ptr->lib_name : "(null)"),
268 (cls_ptr->lib_vers ? cls_ptr->lib_vers : "(null)"));
269
270 /* try show the process or thread id in multiple processes cases*/
271 #ifdef H5_HAVE_PARALLEL
272 {
273 int mpi_rank, mpi_initialized, mpi_finalized;
274
275 MPI_Initialized(&mpi_initialized);
276 MPI_Finalized(&mpi_finalized);
277
278 if(mpi_initialized && !mpi_finalized) {
279 MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
280 fprintf(stream, "MPI-process %d", mpi_rank);
281 } /* end if */
282 else
283 fprintf(stream, "thread 0");
284 } /* end block */
285 #elif defined(H5_HAVE_THREADSAFE)
286 fprintf(stream, "thread %lu", (unsigned long)HDpthread_self_ulong());
287 #else
288 fprintf(stream, "thread 0");
289 #endif
290 fprintf(stream, ":\n");
291 } /* end if */
292
293 /* Check for "real" error description - used to format output more nicely */
294 if(err_desc->desc == NULL || HDstrlen(err_desc->desc) == 0)
295 have_desc=0;
296
297 /* Print error message */
298 fprintf(stream, "%*s#%03d: %s line %u in %s()%s%s\n",
299 H5E_INDENT, "", n, err_desc->file_name, err_desc->line,
300 err_desc->func_name, (have_desc ? ": " : ""),
301 (have_desc ? err_desc->desc : ""));
302 fprintf(stream, "%*smajor: %s\n", (H5E_INDENT * 2), "", maj_str);
303 fprintf(stream, "%*sminor: %s\n", (H5E_INDENT * 2), "", min_str);
304
305 done:
306 FUNC_LEAVE_NOAPI(ret_value)
307 } /* end H5E_walk1_cb() */
308 #endif /* H5_NO_DEPRECATED_SYMBOLS */
309
310
311 /*-------------------------------------------------------------------------
312 * Function: H5E_walk2_cb
313 *
314 * Purpose: This is a default error stack traversal callback function
315 * that prints error messages to the specified output stream.
316 * It is not meant to be called directly but rather as an
317 * argument to the H5Ewalk2() function. This function is
318 * called also by H5Eprint2(). Application writers are
319 * encouraged to use this function as a model for their own
320 * error stack walking functions.
321 *
322 * N is a counter for how many times this function has been
323 * called for this particular traversal of the stack. It always
324 * begins at zero for the first error on the stack (either the
325 * top or bottom error, or even both, depending on the traversal
326 * direction and the size of the stack).
327 *
328 * ERR_DESC is an error description. It contains all the
329 * information about a particular error.
330 *
331 * CLIENT_DATA is the same pointer that was passed as the
332 * CLIENT_DATA argument of H5Ewalk(). It is expected to be a
333 * file pointer (or stderr if null).
334 *
335 * Return: Non-negative on success/Negative on failure
336 *
337 * Programmer: Robb Matzke
338 * Friday, December 12, 1997
339 *
340 *-------------------------------------------------------------------------
341 */
342 static herr_t
H5E_walk2_cb(unsigned n,const H5E_error2_t * err_desc,void * client_data)343 H5E_walk2_cb(unsigned n, const H5E_error2_t *err_desc, void *client_data)
344 {
345 H5E_print_t *eprint = (H5E_print_t *)client_data;
346 FILE *stream; /* I/O stream to print output to */
347 H5E_cls_t *cls_ptr; /* Pointer to error class */
348 H5E_msg_t *maj_ptr; /* Pointer to major error info */
349 H5E_msg_t *min_ptr; /* Pointer to minor error info */
350 const char *maj_str = "No major description"; /* Major error description */
351 const char *min_str = "No minor description"; /* Minor error description */
352 unsigned have_desc = 1; /* Flag to indicate whether the error has a "real" description */
353 herr_t ret_value = SUCCEED;
354
355 FUNC_ENTER_NOAPI_NOINIT_NOERR
356
357 /* Check arguments */
358 HDassert(err_desc);
359
360 /* If no client data was passed, output to stderr */
361 if(!client_data)
362 stream = stderr;
363 else
364 stream = eprint->stream;
365
366 /* Get descriptions for the major and minor error numbers */
367 maj_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->maj_num, H5I_ERROR_MSG);
368 min_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->min_num, H5I_ERROR_MSG);
369
370 /* Check for bad pointer(s), but can't issue error, just leave */
371 if(!maj_ptr || !min_ptr)
372 HGOTO_DONE(FAIL)
373
374 if(maj_ptr->msg)
375 maj_str = maj_ptr->msg;
376 if(min_ptr->msg)
377 min_str = min_ptr->msg;
378
379 /* Get error class info. Don't use the class of the major or minor error because
380 * they might be different. */
381 cls_ptr = (H5E_cls_t *)H5I_object_verify(err_desc->cls_id, H5I_ERROR_CLASS);
382
383 /* Check for bad pointer(s), but can't issue error, just leave */
384 if(!cls_ptr)
385 HGOTO_DONE(FAIL)
386
387 /* Print error class header if new class */
388 if(eprint->cls.lib_name == NULL || HDstrcmp(cls_ptr->lib_name, eprint->cls.lib_name)) {
389 /* update to the new class information */
390 if(cls_ptr->cls_name)
391 eprint->cls.cls_name = cls_ptr->cls_name;
392 if(cls_ptr->lib_name)
393 eprint->cls.lib_name = cls_ptr->lib_name;
394 if(cls_ptr->lib_vers)
395 eprint->cls.lib_vers = cls_ptr->lib_vers;
396
397 fprintf(stream, "%s-DIAG: Error detected in %s (%s) ",
398 (cls_ptr->cls_name ? cls_ptr->cls_name : "(null)"),
399 (cls_ptr->lib_name ? cls_ptr->lib_name : "(null)"),
400 (cls_ptr->lib_vers ? cls_ptr->lib_vers : "(null)"));
401
402 /* try show the process or thread id in multiple processes cases*/
403 #ifdef H5_HAVE_PARALLEL
404 {
405 int mpi_rank, mpi_initialized, mpi_finalized;
406
407 MPI_Initialized(&mpi_initialized);
408 MPI_Finalized(&mpi_finalized);
409
410 if(mpi_initialized && !mpi_finalized) {
411 MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
412 fprintf(stream, "MPI-process %d", mpi_rank);
413 } /* end if */
414 else
415 fprintf(stream, "thread 0");
416 } /* end block */
417 #elif defined(H5_HAVE_THREADSAFE)
418 fprintf(stream, "thread %lu", (unsigned long)HDpthread_self_ulong());
419 #else
420 fprintf(stream, "thread 0");
421 #endif
422 fprintf(stream, ":\n");
423 } /* end if */
424
425 /* Check for "real" error description - used to format output more nicely */
426 if(err_desc->desc == NULL || HDstrlen(err_desc->desc) == 0)
427 have_desc = 0;
428
429 /* Print error message */
430 fprintf(stream, "%*s#%03u: %s line %u in %s()%s%s\n",
431 H5E_INDENT, "", n, err_desc->file_name, err_desc->line,
432 err_desc->func_name, (have_desc ? ": " : ""),
433 (have_desc ? err_desc->desc : ""));
434 fprintf(stream, "%*smajor: %s\n", (H5E_INDENT * 2), "", maj_str);
435 fprintf(stream, "%*sminor: %s\n", (H5E_INDENT * 2), "", min_str);
436
437 done:
438 FUNC_LEAVE_NOAPI(ret_value)
439 } /* end H5E_walk2_cb() */
440
441
442 /*-------------------------------------------------------------------------
443 * Function: H5E_print
444 *
445 * Purpose: Private function to print the error stack in some default
446 * way. This is just a convenience function for H5Ewalk() and
447 * H5Ewalk2() with a function that prints error messages.
448 * Users are encouraged to write there own more specific error
449 * handlers.
450 *
451 * Return: Non-negative on success/Negative on failure
452 *
453 * Programmer: Robb Matzke
454 * Friday, February 27, 1998
455 *
456 *-------------------------------------------------------------------------
457 */
458 herr_t
H5E_print(const H5E_t * estack,FILE * stream,hbool_t bk_compatible)459 H5E_print(const H5E_t *estack, FILE *stream, hbool_t bk_compatible)
460 {
461 H5E_print_t eprint; /* Callback information to pass to H5E_walk() */
462 H5E_walk_op_t walk_op; /* Error stack walking callback */
463 herr_t ret_value = SUCCEED;
464
465 FUNC_ENTER_NOAPI_NOINIT
466
467 /* Sanity check */
468 HDassert(estack);
469
470 /* If no stream was given, use stderr */
471 if(!stream)
472 eprint.stream = stderr;
473 else
474 eprint.stream = stream;
475
476 /* Reset the original error class information */
477 HDmemset(&eprint.cls, 0, sizeof(H5E_cls_t));
478
479 /* Walk the error stack */
480 if(bk_compatible) {
481 #ifndef H5_NO_DEPRECATED_SYMBOLS
482 walk_op.vers = 1;
483 walk_op.u.func1 = H5E_walk1_cb;
484 if(H5E_walk(estack, H5E_WALK_DOWNWARD, &walk_op, (void*)&eprint) < 0)
485 HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack")
486 #else /* H5_NO_DEPRECATED_SYMBOLS */
487 HDassert(0 && "version 1 error stack print without deprecated symbols!");
488 #endif /* H5_NO_DEPRECATED_SYMBOLS */
489 } /* end if */
490 else {
491 walk_op.vers = 2;
492 walk_op.u.func2 = H5E_walk2_cb;
493 if(H5E_walk(estack, H5E_WALK_DOWNWARD, &walk_op, (void*)&eprint) < 0)
494 HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack")
495 } /* end else */
496
497 done:
498 FUNC_LEAVE_NOAPI(ret_value)
499 } /* end H5E_print() */
500
501
502 /*-------------------------------------------------------------------------
503 * Function: H5E_walk
504 *
505 * Purpose: Private function for H5Ewalk.
506 * Walks the error stack, calling the specified function for
507 * each error on the stack. The DIRECTION argument determines
508 * whether the stack is walked from the inside out or the
509 * outside in. The value H5E_WALK_UPWARD means begin with the
510 * most specific error and end at the API; H5E_WALK_DOWNWARD
511 * means to start at the API and end at the inner-most function
512 * where the error was first detected.
513 *
514 * The function pointed to by STACK_FUNC will be called for
515 * each error record in the error stack. It's arguments will
516 * include an index number (beginning at zero regardless of
517 * stack traversal direction), an error stack entry, and the
518 * CLIENT_DATA pointer passed to H5E_print.
519 *
520 * The function FUNC is also provided for backward compatibility.
521 * When BK_COMPATIBLE is set to be TRUE, FUNC is used to be
522 * compatible with older library. If BK_COMPATIBLE is FALSE,
523 * STACK_FUNC is used.
524 *
525 * Return: Non-negative on success/Negative on failure
526 *
527 * Programmer: Robb Matzke
528 * Friday, December 12, 1997
529 *
530 *-------------------------------------------------------------------------
531 */
532 herr_t
H5E_walk(const H5E_t * estack,H5E_direction_t direction,const H5E_walk_op_t * op,void * client_data)533 H5E_walk(const H5E_t *estack, H5E_direction_t direction, const H5E_walk_op_t *op,
534 void *client_data)
535 {
536 int i; /* Local index variable */
537 herr_t status; /* Status from callback function */
538 herr_t ret_value = SUCCEED; /* Return value */
539
540 FUNC_ENTER_NOAPI_NOINIT
541
542 /* Sanity check */
543 HDassert(estack);
544 HDassert(op);
545
546 /* check args, but rather than failing use some default value */
547 if(direction != H5E_WALK_UPWARD && direction != H5E_WALK_DOWNWARD)
548 direction = H5E_WALK_UPWARD;
549
550 /* Walk the stack if a callback function was given */
551 if(op->vers == 1) {
552 #ifndef H5_NO_DEPRECATED_SYMBOLS
553 if(op->u.func1) {
554 H5E_error1_t old_err;
555
556 status = SUCCEED;
557 if(H5E_WALK_UPWARD == direction) {
558 for(i = 0; i < (int)estack->nused && status >= 0; i++) {
559 /* Point to each error record on the stack and pass it to callback function.*/
560 old_err.maj_num = estack->slot[i].maj_num;
561 old_err.min_num = estack->slot[i].min_num;
562 old_err.func_name = estack->slot[i].func_name;
563 old_err.file_name = estack->slot[i].file_name;
564 old_err.desc = estack->slot[i].desc;
565 old_err.line = estack->slot[i].line;
566
567 status = (op->u.func1)(i, &old_err, client_data);
568 } /* end for */
569 } /* end if */
570 else {
571 H5_CHECK_OVERFLOW(estack->nused - 1, size_t, int);
572 for(i = (int)(estack->nused - 1); i >= 0 && status >= 0; i--) {
573 /* Point to each error record on the stack and pass it to callback function.*/
574 old_err.maj_num = estack->slot[i].maj_num;
575 old_err.min_num = estack->slot[i].min_num;
576 old_err.func_name = estack->slot[i].func_name;
577 old_err.file_name = estack->slot[i].file_name;
578 old_err.desc = estack->slot[i].desc;
579 old_err.line = estack->slot[i].line;
580
581 status = (op->u.func1)((int)(estack->nused - (size_t)(i + 1)), &old_err, client_data);
582 } /* end for */
583 } /* end else */
584
585 if(status < 0)
586 HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack")
587 } /* end if */
588 #else /* H5_NO_DEPRECATED_SYMBOLS */
589 HDassert(0 && "version 1 error stack walk without deprecated symbols!");
590 #endif /* H5_NO_DEPRECATED_SYMBOLS */
591 } /* end if */
592 else {
593 HDassert(op->vers == 2);
594 if(op->u.func2) {
595 status = SUCCEED;
596 if(H5E_WALK_UPWARD == direction) {
597 for(i = 0; i < (int)estack->nused && status >= 0; i++)
598 status = (op->u.func2)((unsigned)i, estack->slot + i, client_data);
599 } /* end if */
600 else {
601 H5_CHECK_OVERFLOW(estack->nused - 1, size_t, int);
602 for(i = (int)(estack->nused - 1); i >= 0 && status >= 0; i--)
603 status = (op->u.func2)((unsigned)(estack->nused - (size_t)(i + 1)), estack->slot + i, client_data);
604 } /* end else */
605
606 if(status < 0)
607 HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack")
608 } /* end if */
609 } /* end else */
610
611 done:
612 FUNC_LEAVE_NOAPI(ret_value)
613 } /* end H5E_walk() */
614
615
616 /*-------------------------------------------------------------------------
617 * Function: H5E_get_auto
618 *
619 * Purpose: Private function to return the current settings for the
620 * automatic error stack traversal function and its data
621 * for specific error stack. Either (or both) arguments may
622 * be null in which case the value is not returned.
623 *
624 * Return: Non-negative on success/Negative on failure
625 *
626 * Programmer: Raymond Lu
627 * July 18, 2003
628 *
629 *-------------------------------------------------------------------------
630 */
631 herr_t
H5E_get_auto(const H5E_t * estack,H5E_auto_op_t * op,void ** client_data)632 H5E_get_auto(const H5E_t *estack, H5E_auto_op_t *op, void **client_data)
633 {
634 FUNC_ENTER_NOAPI_NOINIT_NOERR
635
636 HDassert(estack);
637
638 /* Retrieve the requested information */
639 if(op)
640 *op = estack->auto_op;
641 if(client_data)
642 *client_data = estack->auto_data;
643
644 FUNC_LEAVE_NOAPI(SUCCEED)
645 } /* end H5E_get_auto2() */
646
647
648 /*-------------------------------------------------------------------------
649 * Function: H5E_set_auto
650 *
651 * Purpose: Private function to turn on or off automatic printing of
652 * errors for certain error stack. When turned on (non-null
653 * FUNC pointer) any API function which returns an error
654 * indication will first call FUNC passing it CLIENT_DATA
655 * as an argument.
656 *
657 * The default values before this function is called are
658 * H5Eprint2() with client data being the standard error stream,
659 * stderr.
660 *
661 * Automatic stack traversal is always in the H5E_WALK_DOWNWARD
662 * direction.
663 *
664 * Return: Non-negative on success/Negative on failure
665 *
666 * Programmer: Robb Matzke
667 * Friday, February 27, 1998
668 *
669 *-------------------------------------------------------------------------
670 */
671 herr_t
H5E_set_auto(H5E_t * estack,const H5E_auto_op_t * op,void * client_data)672 H5E_set_auto(H5E_t *estack, const H5E_auto_op_t *op, void *client_data)
673 {
674 FUNC_ENTER_NOAPI_NOINIT_NOERR
675
676 HDassert(estack);
677
678 /* Set the automatic error reporting info */
679 estack->auto_op = *op;
680 estack->auto_data = client_data;
681
682 FUNC_LEAVE_NOAPI(SUCCEED)
683 } /* end H5E_set_auto() */
684
685
686 /*-------------------------------------------------------------------------
687 * Function: H5E_printf_stack
688 *
689 * Purpose: Printf-like wrapper around H5E_push_stack.
690 *
691 * Return: Non-negative on success/Negative on failure
692 *
693 * Programmer: Quincey Koziol
694 * Tuesday, August 12, 2008
695 *
696 *-------------------------------------------------------------------------
697 */
698 herr_t
H5E_printf_stack(H5E_t * estack,const char * file,const char * func,unsigned line,hid_t cls_id,hid_t maj_id,hid_t min_id,const char * fmt,...)699 H5E_printf_stack(H5E_t *estack, const char *file, const char *func, unsigned line,
700 hid_t cls_id, hid_t maj_id, hid_t min_id, const char *fmt, ...)
701 {
702 va_list ap; /* Varargs info */
703 #ifndef H5_HAVE_VASPRINTF
704 int tmp_len; /* Current size of description buffer */
705 int desc_len; /* Actual length of description when formatted */
706 #endif /* H5_HAVE_VASPRINTF */
707 char *tmp = NULL; /* Buffer to place formatted description in */
708 hbool_t va_started = FALSE; /* Whether the variable argument list is open */
709 herr_t ret_value = SUCCEED; /* Return value */
710
711 /*
712 * WARNING: We cannot call HERROR() from within this function or else we
713 * could enter infinite recursion. Furthermore, we also cannot
714 * call any other HDF5 macro or function which might call
715 * HERROR(). HERROR() is called by HRETURN_ERROR() which could
716 * be called by FUNC_ENTER().
717 */
718 FUNC_ENTER_NOAPI_NOINIT_NOERR
719
720 /* Sanity check */
721 HDassert(cls_id > 0);
722 HDassert(maj_id > 0);
723 HDassert(min_id > 0);
724 HDassert(fmt);
725
726 /* Note that the variable-argument parsing for the format is identical in
727 * the H5Epush2() routine - correct errors and make changes in both
728 * places. -QAK
729 */
730
731 /* Start the variable-argument parsing */
732 va_start(ap, fmt);
733 va_started = TRUE;
734
735 #ifdef H5_HAVE_VASPRINTF
736 /* Use the vasprintf() routine, since it does what we're trying to do below */
737 if(HDvasprintf(&tmp, fmt, ap) < 0)
738 HGOTO_DONE(FAIL)
739 #else /* H5_HAVE_VASPRINTF */
740 /* Allocate space for the formatted description buffer */
741 tmp_len = 128;
742 if(NULL == (tmp = H5MM_malloc((size_t)tmp_len)))
743 HGOTO_DONE(FAIL)
744
745 /* If the description doesn't fit into the initial buffer size, allocate more space and try again */
746 while((desc_len = HDvsnprintf(tmp, (size_t)tmp_len, fmt, ap)) > (tmp_len - 1)) {
747 /* shutdown & restart the va_list */
748 va_end(ap);
749 va_start(ap, fmt);
750
751 /* Release the previous description, it's too small */
752 H5MM_xfree(tmp);
753
754 /* Allocate a description of the appropriate length */
755 tmp_len = desc_len + 1;
756 if(NULL == (tmp = H5MM_malloc((size_t)tmp_len)))
757 HGOTO_DONE(FAIL)
758 } /* end while */
759 #endif /* H5_HAVE_VASPRINTF */
760
761 /* Push the error on the stack */
762 if(H5E_push_stack(estack, file, func, line, cls_id, maj_id, min_id, tmp) < 0)
763 HGOTO_DONE(FAIL)
764
765 done:
766 if(va_started)
767 va_end(ap);
768 if(tmp)
769 H5MM_xfree(tmp);
770
771 FUNC_LEAVE_NOAPI(ret_value)
772 } /* end H5E_printf_stack() */
773
774
775 /*-------------------------------------------------------------------------
776 * Function: H5E_push_stack
777 *
778 * Purpose: Pushes a new error record onto error stack for the current
779 * thread. The error has major and minor IDs MAJ_ID and
780 * MIN_ID, the name of a function where the error was detected,
781 * the name of the file where the error was detected, the
782 * line within that file, and an error description string. The
783 * function name, file name, and error description strings must
784 * be statically allocated (the FUNC_ENTER() macro takes care of
785 * the function name and file name automatically, but the
786 * programmer is responsible for the description string).
787 *
788 * Return: Non-negative on success/Negative on failure
789 *
790 * Programmer: Robb Matzke
791 * Friday, December 12, 1997
792 *
793 *-------------------------------------------------------------------------
794 */
795 herr_t
H5E_push_stack(H5E_t * estack,const char * file,const char * func,unsigned line,hid_t cls_id,hid_t maj_id,hid_t min_id,const char * desc)796 H5E_push_stack(H5E_t *estack, const char *file, const char *func, unsigned line,
797 hid_t cls_id, hid_t maj_id, hid_t min_id, const char *desc)
798 {
799 herr_t ret_value = SUCCEED; /* Return value */
800
801 /*
802 * WARNING: We cannot call HERROR() from within this function or else we
803 * could enter infinite recursion. Furthermore, we also cannot
804 * call any other HDF5 macro or function which might call
805 * HERROR(). HERROR() is called by HRETURN_ERROR() which could
806 * be called by FUNC_ENTER().
807 */
808 FUNC_ENTER_NOAPI_NOINIT_NOERR
809
810 /* Sanity check */
811 HDassert(cls_id > 0);
812 HDassert(maj_id > 0);
813 HDassert(min_id > 0);
814
815 /* Check for 'default' error stack */
816 if(estack == NULL)
817 if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
818 HGOTO_DONE(FAIL)
819
820 /*
821 * Don't fail if arguments are bad. Instead, substitute some default
822 * value.
823 */
824 if(!func)
825 func = "Unknown_Function";
826 if(!file)
827 file = "Unknown_File";
828 if(!desc)
829 desc = "No description given";
830
831 /*
832 * Push the error if there's room. Otherwise just forget it.
833 */
834 HDassert(estack);
835
836 if(estack->nused < H5E_NSLOTS) {
837 /* Increment the IDs to indicate that they are used in this stack */
838 if(H5I_inc_ref(cls_id, FALSE) < 0)
839 HGOTO_DONE(FAIL)
840 estack->slot[estack->nused].cls_id = cls_id;
841 if(H5I_inc_ref(maj_id, FALSE) < 0)
842 HGOTO_DONE(FAIL)
843 estack->slot[estack->nused].maj_num = maj_id;
844 if(H5I_inc_ref(min_id, FALSE) < 0)
845 HGOTO_DONE(FAIL)
846 estack->slot[estack->nused].min_num = min_id;
847 if(NULL == (estack->slot[estack->nused].func_name = H5MM_xstrdup(func)))
848 HGOTO_DONE(FAIL)
849 if(NULL == (estack->slot[estack->nused].file_name = H5MM_xstrdup(file)))
850 HGOTO_DONE(FAIL)
851 estack->slot[estack->nused].line = line;
852 if(NULL == (estack->slot[estack->nused].desc = H5MM_xstrdup(desc)))
853 HGOTO_DONE(FAIL)
854 estack->nused++;
855 } /* end if */
856
857 done:
858 FUNC_LEAVE_NOAPI(ret_value)
859 } /* end H5E_push_stack() */
860
861
862 /*-------------------------------------------------------------------------
863 * Function: H5E_clear_entries
864 *
865 * Purpose: Private function to clear the error stack entries for the
866 * specified error stack.
867 *
868 * Return: Non-negative on success/Negative on failure
869 *
870 * Programmer: Quincey Koziol
871 * Wednesday, August 6, 2003
872 *
873 *-------------------------------------------------------------------------
874 */
875 static herr_t
H5E_clear_entries(H5E_t * estack,size_t nentries)876 H5E_clear_entries(H5E_t *estack, size_t nentries)
877 {
878 H5E_error2_t *error; /* Pointer to error stack entry to clear */
879 unsigned u; /* Local index variable */
880 herr_t ret_value=SUCCEED; /* Return value */
881
882 FUNC_ENTER_NOAPI_NOINIT
883
884 /* Sanity check */
885 HDassert(estack);
886 HDassert(estack->nused >= nentries);
887
888 /* Empty the error stack from the top down */
889 for(u = 0; nentries > 0; nentries--, u++) {
890 error = &(estack->slot[estack->nused - (u + 1)]);
891
892 /* Decrement the IDs to indicate that they are no longer used by this stack */
893 /* (In reverse order that they were incremented, so that reference counts work well) */
894 if(H5I_dec_ref(error->min_num) < 0)
895 HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error message")
896 if(H5I_dec_ref(error->maj_num) < 0)
897 HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error message")
898 if(H5I_dec_ref(error->cls_id) < 0)
899 HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error class")
900
901 /* Release strings */
902 if(error->func_name)
903 H5MM_xfree((void *)error->func_name); /* Casting away const OK - QAK */
904 if(error->file_name)
905 H5MM_xfree((void *)error->file_name); /* Casting away const OK - QAK */
906 if(error->desc)
907 H5MM_xfree((void *)error->desc); /* Casting away const OK - QAK */
908 } /* end for */
909
910 /* Decrement number of errors on stack */
911 estack->nused -= u;
912
913 done:
914 FUNC_LEAVE_NOAPI(ret_value)
915 } /* end H5E_clear_entries() */
916
917
918 /*-------------------------------------------------------------------------
919 * Function: H5E_clear_stack
920 *
921 * Purpose: Private function to clear the error stack for the
922 * specified error stack.
923 *
924 * Return: Non-negative on success/Negative on failure
925 *
926 * Programmer: Raymond Lu
927 * Wednesday, July 16, 2003
928 *
929 *-------------------------------------------------------------------------
930 */
931 herr_t
H5E_clear_stack(H5E_t * estack)932 H5E_clear_stack(H5E_t *estack)
933 {
934 herr_t ret_value = SUCCEED; /* Return value */
935
936 FUNC_ENTER_NOAPI(FAIL)
937
938 /* Check for 'default' error stack */
939 if(estack == NULL)
940 if(NULL == (estack = H5E_get_my_stack())) /*lint !e506 !e774 Make lint 'constant value Boolean' in non-threaded case */
941 HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack")
942
943 /* Empty the error stack */
944 HDassert(estack);
945 if(estack->nused)
946 if(H5E_clear_entries(estack, estack->nused) < 0)
947 HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't clear error stack")
948
949 done:
950 FUNC_LEAVE_NOAPI(ret_value)
951 } /* end H5E_clear_stack() */
952
953
954 /*-------------------------------------------------------------------------
955 * Function: H5E_pop
956 *
957 * Purpose: Private function to delete some error messages from the top
958 * of error stack.
959 *
960 * Return: Non-negative value on success/Negative on failure
961 *
962 * Programmer: Raymond Lu
963 * Friday, July 16, 2003
964 *
965 *-------------------------------------------------------------------------
966 */
967 herr_t
H5E_pop(H5E_t * estack,size_t count)968 H5E_pop(H5E_t *estack, size_t count)
969 {
970 herr_t ret_value = SUCCEED; /* Return value */
971
972 FUNC_ENTER_NOAPI_NOINIT
973
974 /* Sanity check */
975 HDassert(estack);
976 HDassert(estack->nused >= count);
977
978 /* Remove the entries from the error stack */
979 if(H5E_clear_entries(estack, count) < 0)
980 HGOTO_ERROR(H5E_ERROR, H5E_CANTRELEASE, FAIL, "can't remove errors from stack")
981
982 done:
983 FUNC_LEAVE_NOAPI(ret_value)
984 } /* end H5E_pop() */
985
986
987 /*-------------------------------------------------------------------------
988 * Function: H5E_dump_api_stack
989 *
990 * Purpose: Private function to dump the error stack during an error in
991 * an API function if a callback function is defined for the
992 * current error stack.
993 *
994 * Return: Non-negative on success/Negative on failure
995 *
996 * Programmer: Quincey Koziol
997 * Wednesday, August 6, 2003
998 *
999 *-------------------------------------------------------------------------
1000 */
1001 herr_t
H5E_dump_api_stack(int is_api)1002 H5E_dump_api_stack(int is_api)
1003 {
1004 herr_t ret_value = SUCCEED; /* Return value */
1005
1006 FUNC_ENTER_NOAPI(FAIL)
1007
1008 /* Only dump the error stack during an API call */
1009 if(is_api) {
1010 H5E_t *estack = H5E_get_my_stack();
1011
1012 HDassert(estack);
1013
1014 #ifdef H5_NO_DEPRECATED_SYMBOLS
1015 if(estack->auto_op.func2)
1016 (void)((estack->auto_op.func2)(H5E_DEFAULT, estack->auto_data));
1017 #else /* H5_NO_DEPRECATED_SYMBOLS */
1018 if(estack->auto_op.vers == 1) {
1019 if(estack->auto_op.func1)
1020 (void)((estack->auto_op.func1)(estack->auto_data));
1021 } /* end if */
1022 else {
1023 if(estack->auto_op.func2)
1024 (void)((estack->auto_op.func2)(H5E_DEFAULT, estack->auto_data));
1025 } /* end else */
1026 #endif /* H5_NO_DEPRECATED_SYMBOLS */
1027 } /* end if */
1028
1029 done:
1030 FUNC_LEAVE_NOAPI(ret_value)
1031 } /* end H5E_dump_api_stack() */
1032
1033