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