Coverage Report

Created: 2026-07-16 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Eint.c
Line
Count
Source
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the LICENSE file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
/*-------------------------------------------------------------------------
14
 *
15
 * Created: H5Eint.c
16
 *
17
 * Purpose: General use, "internal" routines for error handling.
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/****************/
23
/* Module Setup */
24
/****************/
25
26
#include "H5Emodule.h" /* This source code file is part of the H5E module */
27
28
/***********/
29
/* Headers */
30
/***********/
31
#include "H5private.h"   /* Generic Functions                        */
32
#include "H5Epkg.h"      /* Error handling                           */
33
#include "H5FLprivate.h" /* Free lists                               */
34
#include "H5Iprivate.h"  /* IDs                                      */
35
#include "H5MMprivate.h" /* Memory management                        */
36
#include "H5TSprivate.h" /* Thread stuff                             */
37
38
/****************/
39
/* Local Macros */
40
/****************/
41
42
/* HDF5 error class */
43
#define H5E_CLS_NAME     "HDF5"
44
#define H5E_CLS_LIB_NAME "HDF5"
45
46
/******************/
47
/* Local Typedefs */
48
/******************/
49
50
/* Printing information */
51
typedef struct H5E_print_t {
52
    FILE     *stream;
53
    H5E_cls_t cls;
54
} H5E_print_t;
55
56
/********************/
57
/* Package Typedefs */
58
/********************/
59
60
/********************/
61
/* Local Prototypes */
62
/********************/
63
#ifndef H5_NO_DEPRECATED_SYMBOLS
64
static herr_t H5E__walk1_cb(int n, H5E_error1_t *err_desc, void *client_data);
65
#endif /* H5_NO_DEPRECATED_SYMBOLS */
66
static herr_t H5E__walk2_cb(unsigned n, const H5E_error2_t *err_desc, void *client_data);
67
static herr_t H5E__copy_stack_entry(H5E_entry_t *dst_entry, const H5E_entry_t *src_entry);
68
static herr_t H5E__set_stack_entry(H5E_error2_t *err_entry, const char *file, const char *func, unsigned line,
69
                                   hid_t cls_id, hid_t maj_id, hid_t min_id, const char *desc, va_list *ap);
70
static herr_t H5E__clear_entries(H5E_stack_t *estack, size_t nentries);
71
static herr_t H5E__unregister_class(void *cls, void **request);
72
static int    H5E__close_msg_cb(void *obj_ptr, hid_t obj_id, void *udata);
73
static void   H5E__free_msg(H5E_msg_t *msg);
74
static herr_t H5E__close_msg(void *err, void **request);
75
static herr_t H5E__close_stack(void *err_stack, void **request);
76
77
/*********************/
78
/* Package Variables */
79
/*********************/
80
81
#ifndef H5_HAVE_THREADSAFE_API
82
/*
83
 * The current error stack.
84
 */
85
H5E_stack_t H5E_stack_g[1];
86
#endif /* H5_HAVE_THREADSAFE_API */
87
88
/* Declare a free list to manage the H5E_stack_t struct */
89
H5FL_DEFINE(H5E_stack_t);
90
91
/* Declare a free list to manage the H5E_cls_t struct */
92
H5FL_DEFINE_STATIC(H5E_cls_t);
93
94
/* Declare a free list to manage the H5E_msg_t struct */
95
H5FL_DEFINE_STATIC(H5E_msg_t);
96
97
/*****************************/
98
/* Library Private Variables */
99
/*****************************/
100
101
/* HDF5 error class ID */
102
hid_t H5E_ERR_CLS_g = FAIL;
103
104
/*
105
 * Predefined errors. These are initialized at runtime in H5E_init_interface()
106
 * in this source file.
107
 */
108
/* Include the automatically generated error code definitions */
109
#include "H5Edefin.h"
110
111
/*******************/
112
/* Local Variables */
113
/*******************/
114
115
/* Default value to initialize error stacks */
116
static const H5E_stack_t H5E_err_stack_def = {
117
    0, /* nused */
118
    {  /*entries[] */
119
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
120
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
121
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
122
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
123
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
124
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
125
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
126
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
127
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
128
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
129
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
130
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
131
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
132
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
133
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
134
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
135
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
136
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
137
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
138
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
139
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
140
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
141
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
142
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
143
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
144
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
145
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
146
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
147
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
148
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
149
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}},
150
     {false, {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, 0, NULL, NULL, NULL}}},
151
152
/* H5E_auto_op_t */
153
#ifndef H5_NO_DEPRECATED_SYMBOLS
154
#ifdef H5_USE_16_API_DEFAULT
155
    {1, true, (H5E_auto1_t)H5Eprint1, H5E__print2, (H5E_auto1_t)H5Eprint1, H5E__print2},
156
#else  /* H5_USE_16_API */
157
    {2, true, (H5E_auto1_t)H5Eprint1, H5E__print2, (H5E_auto1_t)H5Eprint1, H5E__print2},
158
#endif /* H5_USE_16_API_DEFAULT */
159
#else  /* H5_NO_DEPRECATED_SYMBOLS */
160
    {H5E__print2},
161
#endif /* H5_NO_DEPRECATED_SYMBOLS */
162
163
    NULL, /* auto_data */
164
    0     /* paused */
165
};
166
167
/* First & last major and minor error codes registered by the library */
168
hid_t H5E_first_maj_id_g = H5I_INVALID_HID;
169
hid_t H5E_last_maj_id_g  = H5I_INVALID_HID;
170
hid_t H5E_first_min_id_g = H5I_INVALID_HID;
171
hid_t H5E_last_min_id_g  = H5I_INVALID_HID;
172
173
/* Error class ID class */
174
static const H5I_class_t H5I_ERRCLS_CLS[1] = {{
175
    H5I_ERROR_CLASS,      /* ID class value */
176
    0,                    /* Class flags */
177
    0,                    /* # of reserved IDs for class */
178
    H5E__unregister_class /* Callback routine for closing objects of this class */
179
}};
180
181
/* Error message ID class */
182
static const H5I_class_t H5I_ERRMSG_CLS[1] = {{
183
    H5I_ERROR_MSG, /* ID class value */
184
    0,             /* Class flags */
185
    0,             /* # of reserved IDs for class */
186
    H5E__close_msg /* Callback routine for closing objects of this class */
187
}};
188
189
/* Error stack ID class */
190
static const H5I_class_t H5I_ERRSTK_CLS[1] = {{
191
    H5I_ERROR_STACK, /* ID class value */
192
    0,               /* Class flags */
193
    0,               /* # of reserved IDs for class */
194
    H5E__close_stack /* Callback routine for closing objects of this class */
195
}};
196
197
/* Library's error class */
198
static const H5E_cls_t H5E_err_cls_s = {false, H5E_CLS_NAME, H5E_CLS_LIB_NAME, H5_VERS_STR};
199
200
/* Include the automatically generated major error message definitions */
201
#include "H5Emajdef.h"
202
203
/* Include the automatically generated minor error message definitions */
204
#include "H5Emindef.h"
205
206
/*-------------------------------------------------------------------------
207
 * Function:    H5E_init
208
 *
209
 * Purpose:     Initialize the interface from some other layer.
210
 *
211
 * Return:      Success:        non-negative
212
 *              Failure:        negative
213
 *-------------------------------------------------------------------------
214
 */
215
herr_t
216
H5E_init(void)
217
1
{
218
1
    herr_t ret_value = SUCCEED; /* Return value */
219
220
1
    FUNC_ENTER_NOAPI(FAIL)
221
    /* FUNC_ENTER() does all the work */
222
223
1
done:
224
1
    FUNC_LEAVE_NOAPI(ret_value)
225
1
} /* end H5E_init() */
226
227
/*--------------------------------------------------------------------------
228
 * Function:    H5E__init_package
229
 *
230
 * Purpose:     Initialize interface-specific information
231
 *
232
 * Return:      SUCCEED/FAIL
233
 *
234
 * Programmer:  Raymond Lu
235
 *              Friday, July 11, 2003
236
 *
237
 *--------------------------------------------------------------------------
238
 */
239
herr_t
240
H5E__init_package(void)
241
1
{
242
1
    herr_t ret_value = SUCCEED; /* Return value */
243
244
1
    FUNC_ENTER_PACKAGE
245
246
    /* Initialize the ID group for the error class IDs */
247
1
    if (H5I_register_type(H5I_ERRCLS_CLS) < 0)
248
0
        HGOTO_ERROR(H5E_ID, H5E_CANTINIT, FAIL, "unable to initialize ID group");
249
250
    /* Initialize the ID group for the major error IDs */
251
1
    if (H5I_register_type(H5I_ERRMSG_CLS) < 0)
252
0
        HGOTO_ERROR(H5E_ID, H5E_CANTINIT, FAIL, "unable to initialize ID group");
253
254
    /* Initialize the ID group for the error stacks */
255
1
    if (H5I_register_type(H5I_ERRSTK_CLS) < 0)
256
0
        HGOTO_ERROR(H5E_ID, H5E_CANTINIT, FAIL, "unable to initialize ID group");
257
258
1
#ifndef H5_HAVE_THREADSAFE_API
259
1
    H5E__set_default_auto(H5E_stack_g);
260
1
#endif /* H5_HAVE_THREADSAFE_API */
261
262
    /* Register the HDF5 error class */
263
1
    if ((H5E_ERR_CLS_g = H5I_register(H5I_ERROR_CLASS, &H5E_err_cls_s, false)) < 0)
264
0
        HGOTO_ERROR(H5E_ERROR, H5E_CANTREGISTER, FAIL, "can't register error class");
265
266
/* Include the automatically generated error code initialization */
267
182
#include "H5Einit.h"
268
269
182
done:
270
1
    FUNC_LEAVE_NOAPI(ret_value)
271
1
} /* end H5E__init_package() */
272
273
/*-------------------------------------------------------------------------
274
 * Function:    H5E_term_package
275
 *
276
 * Purpose:     Terminates the H5E interface
277
 *
278
 * Return:      Success:    Positive if anything is done that might
279
 *                          affect other interfaces; zero otherwise.
280
 *
281
 *              Failure:    Negative
282
 *
283
 *-------------------------------------------------------------------------
284
 */
285
int
286
H5E_term_package(void)
287
3
{
288
3
    int n = 0;
289
290
3
    FUNC_ENTER_NOAPI_NOINIT_NOERR
291
292
2
    if (H5_PKG_INIT_VAR) {
293
2
        int64_t ncls, nmsg, nstk;
294
295
        /* Check if there are any open error stacks, classes or messages */
296
2
        ncls = H5I_nmembers(H5I_ERROR_CLASS);
297
2
        nmsg = H5I_nmembers(H5I_ERROR_MSG);
298
2
        nstk = H5I_nmembers(H5I_ERROR_STACK);
299
300
2
        if ((ncls + nmsg + nstk) > 0) {
301
            /* Clear the default error stack. Note that
302
             * the following H5I_clear_type calls do not
303
             * force the clears and will not be able to
304
             * clear any error message IDs that are still
305
             * in use by the default error stack unless we
306
             * clear that stack manually.
307
             *
308
             * Error message IDs will typically still be
309
             * in use by the default error stack when the
310
             * application does H5E_BEGIN/END_TRY cleanup
311
             * at the very end.
312
             */
313
1
            H5E_clear_stack();
314
315
            /* Clear any outstanding error stacks */
316
1
            if (nstk > 0)
317
0
                (void)H5I_clear_type(H5I_ERROR_STACK, false, false);
318
319
            /* Clear all the error classes */
320
1
            if (ncls > 0) {
321
1
                (void)H5I_clear_type(H5I_ERROR_CLASS, false, false);
322
323
                /* Reset the HDF5 error class, if its been closed */
324
1
                if (H5I_nmembers(H5I_ERROR_CLASS) == 0)
325
1
                    H5E_ERR_CLS_g = H5I_INVALID_HID;
326
1
            } /* end if */
327
328
            /* Clear all the error messages */
329
1
            if (nmsg > 0) {
330
1
                (void)H5I_clear_type(H5I_ERROR_MSG, false, false);
331
332
                /* Reset the HDF5 error messages, if they've been closed */
333
1
                if (H5I_nmembers(H5I_ERROR_MSG) == 0) {
334
/* Include the automatically generated error code termination */
335
1
#include "H5Eterm.h"
336
1
                } /* end if */
337
1
            }     /* end if */
338
339
1
            n++; /*H5I*/
340
1
        }        /* end if */
341
1
        else {
342
            /* Destroy the error class, message, and stack id groups */
343
1
            n += (H5I_dec_type_ref(H5I_ERROR_STACK) > 0);
344
1
            n += (H5I_dec_type_ref(H5I_ERROR_CLASS) > 0);
345
1
            n += (H5I_dec_type_ref(H5I_ERROR_MSG) > 0);
346
347
            /* Mark closed */
348
1
            if (0 == n)
349
1
                H5_PKG_INIT_VAR = false;
350
1
        } /* end else */
351
2
    }     /* end if */
352
353
2
    FUNC_LEAVE_NOAPI(n)
354
3
} /* end H5E_term_package() */
355
356
/*-------------------------------------------------------------------------
357
 * Function:    H5E_user_cb_prepare
358
 *
359
 * Purpose:     Prepare the H5E package before a user callback
360
 *
361
 * Return:      SUCCEED/FAIL
362
 *
363
 *-------------------------------------------------------------------------
364
 */
365
herr_t
366
H5E_user_cb_prepare(H5E_user_cb_state_t *state)
367
1.06k
{
368
1.06k
    H5E_stack_t *stack;               /* Pointer to the current error stack */
369
1.06k
    herr_t       ret_value = SUCCEED; /* Return value */
370
371
1.06k
    FUNC_ENTER_NOAPI(FAIL)
372
373
    /* Get a pointer to the current error stack */
374
1.06k
    if (NULL == (stack = H5E__get_my_stack()))
375
0
        HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack");
376
377
        /* Save state for current error stack */
378
1.06k
#ifndef H5_NO_DEPRECATED_SYMBOLS
379
1.06k
    assert(1 == stack->auto_op.vers || 2 == stack->auto_op.vers);
380
381
1.06k
    state->vers = stack->auto_op.vers;
382
1.06k
    if (1 == stack->auto_op.vers)
383
0
        state->u.func1 = stack->auto_op.func1;
384
1.06k
    else
385
1.06k
        state->u.func2 = stack->auto_op.func2;
386
#else  /* H5_NO_DEPRECATED_SYMBOLS */
387
    state->func2 = stack->auto_op.func2;
388
#endif /* H5_NO_DEPRECATED_SYMBOLS */
389
1.06k
    state->data = stack->auto_data;
390
391
1.06k
done:
392
1.06k
    FUNC_LEAVE_NOAPI(ret_value)
393
1.06k
} /* end H5E_user_cb_prepare() */
394
395
/*-------------------------------------------------------------------------
396
 * Function:    H5E_user_cb_restore
397
 *
398
 * Purpose:     Restores the state of the H5E package after a user callback
399
 *
400
 * Return:      SUCCEED/FAIL
401
 *
402
 *-------------------------------------------------------------------------
403
 */
404
herr_t
405
H5E_user_cb_restore(const H5E_user_cb_state_t *state)
406
1.06k
{
407
1.06k
    H5E_stack_t *stack;               /* Pointer to the current error stack */
408
1.06k
    herr_t       ret_value = SUCCEED; /* Return value */
409
410
1.06k
    FUNC_ENTER_NOAPI(FAIL)
411
412
    /* Get a pointer to the current error stack */
413
1.06k
    if (NULL == (stack = H5E__get_my_stack()))
414
0
        HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack");
415
416
        /* Restore state for current error stack */
417
1.06k
#ifndef H5_NO_DEPRECATED_SYMBOLS
418
1.06k
    stack->auto_op.vers = state->vers;
419
1.06k
    if (1 == state->vers)
420
0
        stack->auto_op.func1 = state->u.func1;
421
1.06k
    else
422
1.06k
        stack->auto_op.func2 = state->u.func2;
423
#else  /* H5_NO_DEPRECATED_SYMBOLS */
424
    stack->auto_op.func2 = state->func2;
425
#endif /* H5_NO_DEPRECATED_SYMBOLS */
426
1.06k
    stack->auto_data = state->data;
427
428
1.06k
done:
429
1.06k
    FUNC_LEAVE_NOAPI(ret_value)
430
1.06k
} /* end H5E_user_cb_restore() */
431
432
/*-------------------------------------------------------------------------
433
 * Function:    H5E__free_class
434
 *
435
 * Purpose:     Private function to free an error class.
436
 *
437
 * Return:      SUCCEED/FAIL
438
 *
439
 *-------------------------------------------------------------------------
440
 */
441
static herr_t
442
H5E__free_class(H5E_cls_t *cls)
443
1
{
444
1
    FUNC_ENTER_PACKAGE_NOERR
445
446
    /* Check arguments */
447
1
    assert(cls);
448
449
    /* Free resources, if application registered this class */
450
1
    if (cls->app_cls) {
451
        /* Free error class structure */
452
0
        cls->cls_name = H5MM_xfree_const(cls->cls_name);
453
0
        cls->lib_name = H5MM_xfree_const(cls->lib_name);
454
0
        cls->lib_vers = H5MM_xfree_const(cls->lib_vers);
455
0
        cls           = H5FL_FREE(H5E_cls_t, cls);
456
0
    }
457
458
1
    FUNC_LEAVE_NOAPI(SUCCEED)
459
1
} /* end H5E__free_class() */
460
461
/*-------------------------------------------------------------------------
462
 * Function:    H5E__register_class
463
 *
464
 * Purpose:     Private function to register an error class.
465
 *
466
 * Return:      Success:    Pointer to an error class struct
467
 *              Failure:    NULL
468
 *
469
 *-------------------------------------------------------------------------
470
 */
471
H5E_cls_t *
472
H5E__register_class(const char *cls_name, const char *lib_name, const char *version)
473
0
{
474
0
    H5E_cls_t *cls       = NULL; /* Pointer to error class */
475
0
    H5E_cls_t *ret_value = NULL; /* Return value */
476
477
0
    FUNC_ENTER_PACKAGE
478
479
    /* Check arguments */
480
0
    assert(cls_name);
481
0
    assert(lib_name);
482
0
    assert(version);
483
484
    /* Allocate space for new error class */
485
0
    if (NULL == (cls = H5FL_CALLOC(H5E_cls_t)))
486
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
487
488
    /* Application registered class */
489
0
    cls->app_cls = true;
490
491
    /* Duplicate string information */
492
0
    if (NULL == (cls->cls_name = strdup(cls_name)))
493
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
494
0
    if (NULL == (cls->lib_name = strdup(lib_name)))
495
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
496
0
    if (NULL == (cls->lib_vers = strdup(version)))
497
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
498
499
    /* Set the return value */
500
0
    ret_value = cls;
501
502
0
done:
503
0
    if (!ret_value)
504
0
        if (cls && H5E__free_class(cls) < 0)
505
0
            HDONE_ERROR(H5E_ERROR, H5E_CANTRELEASE, NULL, "unable to free error class");
506
507
0
    FUNC_LEAVE_NOAPI(ret_value)
508
0
} /* end H5E__register_class() */
509
510
/*-------------------------------------------------------------------------
511
 * Function:    H5E__unregister_class
512
 *
513
 * Purpose:     Private function to close an error class.
514
 *
515
 * Return:      SUCCEED/FAIL
516
 *
517
 *-------------------------------------------------------------------------
518
 */
519
static herr_t
520
H5E__unregister_class(void *cls, void H5_ATTR_UNUSED **request)
521
1
{
522
1
    H5E_cls_t *cls_p     = (H5E_cls_t *)cls;
523
1
    herr_t     ret_value = SUCCEED; /* Return value */
524
525
1
    FUNC_ENTER_PACKAGE
526
527
    /* Check arguments */
528
1
    assert(cls_p);
529
530
    /* Iterate over all the messages and delete those in this error class */
531
1
    if (H5I_iterate(H5I_ERROR_MSG, H5E__close_msg_cb, cls_p, false) < 0)
532
0
        HGOTO_ERROR(H5E_ERROR, H5E_BADITER, FAIL, "unable to free all messages in this error class");
533
534
    /* Free error class structure */
535
1
    if (H5E__free_class(cls_p) < 0)
536
0
        HGOTO_ERROR(H5E_ERROR, H5E_CANTRELEASE, FAIL, "unable to free error class");
537
538
1
done:
539
1
    FUNC_LEAVE_NOAPI(ret_value)
540
1
} /* end H5E__unregister_class() */
541
542
/*-------------------------------------------------------------------------
543
 * Function:    H5E__get_class_name
544
 *
545
 * Purpose:     Private function to retrieve error class name.
546
 *
547
 * Return:      Success:    Name length (zero means no name)
548
 *              Failure:    -1
549
 *
550
 *-------------------------------------------------------------------------
551
 */
552
ssize_t
553
H5E__get_class_name(const H5E_cls_t *cls, char *name, size_t size)
554
0
{
555
0
    ssize_t len = -1; /* Length of error class's name */
556
557
0
    FUNC_ENTER_PACKAGE_NOERR
558
559
    /* Check arguments */
560
0
    assert(cls);
561
562
    /* Get the class's name */
563
0
    len = (ssize_t)strlen(cls->cls_name);
564
565
    /* Set the user's buffer, if provided */
566
0
    if (name) {
567
0
        strncpy(name, cls->cls_name, size);
568
0
        if ((size_t)len >= size)
569
0
            name[size - 1] = '\0';
570
0
    } /* end if */
571
572
    /* Return the full length */
573
0
    FUNC_LEAVE_NOAPI(len)
574
0
} /* end H5E__get_class_name() */
575
576
/*-------------------------------------------------------------------------
577
 * Function:    H5E__close_msg_cb
578
 *
579
 * Purpose:     H5I_iterate callback function to close error messages in the
580
 *              error class.
581
 *
582
 * Return:      Success:    H5_ITER_CONT (0)
583
 *              Failure:    H5_ITER_ERROR (-1)
584
 *
585
 *-------------------------------------------------------------------------
586
 */
587
static int
588
H5E__close_msg_cb(void *obj_ptr, hid_t obj_id, void *udata)
589
181
{
590
181
    H5E_msg_t *err_msg   = (H5E_msg_t *)obj_ptr;
591
181
    H5E_cls_t *cls       = (H5E_cls_t *)udata;
592
181
    int        ret_value = H5_ITER_CONT; /* Return value */
593
594
181
    FUNC_ENTER_PACKAGE
595
596
    /* Check arguments */
597
181
    assert(err_msg);
598
599
    /* Close the message if it is in the class being closed */
600
181
    if (err_msg->cls == cls) {
601
181
        if (H5E__close_msg(err_msg, NULL) < 0)
602
0
            HGOTO_ERROR(H5E_ERROR, H5E_CANTCLOSEOBJ, H5_ITER_ERROR, "unable to close error message");
603
181
        if (NULL == H5I_remove(obj_id))
604
0
            HGOTO_ERROR(H5E_ERROR, H5E_CANTREMOVE, H5_ITER_ERROR, "unable to remove error message");
605
181
    } /* end if */
606
607
181
done:
608
181
    FUNC_LEAVE_NOAPI(ret_value)
609
181
} /* end H5E__close_msg_cb() */
610
611
/*-------------------------------------------------------------------------
612
 * Function:    H5E__free_msg
613
 *
614
 * Purpose:     Private function to free an application error message.
615
 *
616
 * Return:      none
617
 *
618
 *-------------------------------------------------------------------------
619
 */
620
static void
621
H5E__free_msg(H5E_msg_t *msg)
622
0
{
623
0
    FUNC_ENTER_PACKAGE_NOERR
624
625
    /* Check arguments */
626
0
    assert(msg);
627
0
    assert(msg->app_msg);
628
629
    /* Free resources */
630
0
    msg->msg = H5MM_xfree_const(msg->msg);
631
0
    msg      = H5FL_FREE(H5E_msg_t, msg);
632
633
0
    FUNC_LEAVE_NOAPI_VOID
634
0
} /* end H5E__free_msg() */
635
636
/*-------------------------------------------------------------------------
637
 * Function:    H5E__close_msg
638
 *
639
 * Purpose:     Private function to close an error message.
640
 *
641
 * Return:      SUCCEED/FAIL
642
 *
643
 *-------------------------------------------------------------------------
644
 */
645
static herr_t
646
H5E__close_msg(void *err, void H5_ATTR_UNUSED **request)
647
181
{
648
181
    H5E_msg_t *err_p = (H5E_msg_t *)err;
649
650
181
    FUNC_ENTER_PACKAGE_NOERR
651
652
    /* Check arguments */
653
181
    assert(err_p);
654
655
    /* Free resources, if application registered this message */
656
181
    if (err_p->app_msg)
657
        /* Free message */
658
0
        H5E__free_msg(err_p);
659
660
181
    FUNC_LEAVE_NOAPI(SUCCEED)
661
181
} /* end H5E__close_msg() */
662
663
/*-------------------------------------------------------------------------
664
 * Function:    H5E__create_msg
665
 *
666
 * Purpose:     Private function to create a major or minor error.
667
 *
668
 * Return:      Success:    Pointer to a message struct
669
 *              Failure:    NULL
670
 *
671
 *-------------------------------------------------------------------------
672
 */
673
H5E_msg_t *
674
H5E__create_msg(H5E_cls_t *cls, H5E_type_t msg_type, const char *msg_str)
675
0
{
676
0
    H5E_msg_t *msg       = NULL; /* Pointer to new error message */
677
0
    H5E_msg_t *ret_value = NULL; /* Return value */
678
679
0
    FUNC_ENTER_PACKAGE
680
681
    /* Check arguments */
682
0
    assert(cls);
683
0
    assert(msg_type == H5E_MAJOR || msg_type == H5E_MINOR);
684
0
    assert(msg_str);
685
686
    /* Allocate new message object */
687
0
    if (NULL == (msg = H5FL_CALLOC(H5E_msg_t)))
688
0
        HGOTO_ERROR(H5E_ERROR, H5E_CANTALLOC, NULL, "memory allocation failed");
689
690
    /* Fill new message object */
691
0
    msg->app_msg = true;
692
0
    msg->cls     = cls;
693
0
    msg->type    = msg_type;
694
0
    if (NULL == (msg->msg = strdup(msg_str)))
695
0
        HGOTO_ERROR(H5E_ERROR, H5E_CANTALLOC, NULL, "memory allocation failed");
696
697
    /* Set return value */
698
0
    ret_value = msg;
699
700
0
done:
701
0
    if (!ret_value)
702
0
        if (msg)
703
0
            H5E__free_msg(msg);
704
705
0
    FUNC_LEAVE_NOAPI(ret_value)
706
0
} /* end H5E__create_msg() */
707
708
/*-------------------------------------------------------------------------
709
 * Function:    H5E__get_current_stack
710
 *
711
 * Purpose:     Private function to register an error stack.
712
 *
713
 * Return:      Success:    Pointer to an error class struct
714
 *              Failure:    NULL
715
 *
716
 *-------------------------------------------------------------------------
717
 */
718
H5E_stack_t *
719
H5E__get_current_stack(void)
720
0
{
721
0
    H5E_stack_t *current_stack;      /* Pointer to the current error stack */
722
0
    H5E_stack_t *estack_copy = NULL; /* Pointer to new error stack to return */
723
0
    unsigned     u;                  /* Local index variable */
724
0
    H5E_stack_t *ret_value = NULL;   /* Return value */
725
726
0
    FUNC_ENTER_PACKAGE
727
728
    /* Get a pointer to the current error stack */
729
0
    if (NULL == (current_stack = H5E__get_my_stack()))
730
0
        HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, NULL, "can't get current error stack");
731
732
    /* Allocate a new error stack */
733
0
    if (NULL == (estack_copy = H5FL_CALLOC(H5E_stack_t)))
734
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
735
736
    /* Make a copy of current error stack */
737
0
    estack_copy->nused = current_stack->nused;
738
0
    for (u = 0; u < current_stack->nused; u++)
739
0
        if (H5E__copy_stack_entry(&estack_copy->entries[u], &current_stack->entries[u]) < 0)
740
0
            HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, NULL, "can't set error entry");
741
742
    /* Copy the "automatic" error reporting information */
743
0
    estack_copy->auto_op   = current_stack->auto_op;
744
0
    estack_copy->auto_data = current_stack->auto_data;
745
746
    /* Empty current error stack */
747
0
    H5E__destroy_stack(current_stack);
748
749
    /* Set the return value */
750
0
    ret_value = estack_copy;
751
752
0
done:
753
0
    if (ret_value == NULL)
754
0
        if (estack_copy)
755
0
            estack_copy = H5FL_FREE(H5E_stack_t, estack_copy);
756
757
0
    FUNC_LEAVE_NOAPI(ret_value)
758
0
} /* end H5E__get_current_stack() */
759
760
/*-------------------------------------------------------------------------
761
 * Function:    H5E__set_current_stack
762
 *
763
 * Purpose:     Private function to replace an error stack.
764
 *
765
 * Return:      SUCCEED/FAIL
766
 *
767
 *-------------------------------------------------------------------------
768
 */
769
herr_t
770
H5E__set_current_stack(H5E_stack_t *estack)
771
0
{
772
0
    H5E_stack_t *current_stack;       /* Default error stack */
773
0
    unsigned     u;                   /* Local index variable */
774
0
    herr_t       ret_value = SUCCEED; /* Return value */
775
776
0
    FUNC_ENTER_PACKAGE
777
778
    /* Sanity check */
779
0
    assert(estack);
780
781
    /* Get a pointer to the current error stack */
782
0
    if (NULL == (current_stack = H5E__get_my_stack()))
783
0
        HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack");
784
785
    /* Empty current error stack */
786
0
    H5E__destroy_stack(current_stack);
787
788
    /* Copy new stack to current error stack */
789
0
    current_stack->nused = estack->nused;
790
0
    for (u = 0; u < current_stack->nused; u++)
791
0
        if (H5E__copy_stack_entry(&current_stack->entries[u], &estack->entries[u]) < 0)
792
0
            HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't set error entry");
793
794
0
done:
795
0
    FUNC_LEAVE_NOAPI(ret_value)
796
0
} /* end H5E__set_current_stack() */
797
798
/*-------------------------------------------------------------------------
799
 * Function:    H5E__close_stack
800
 *
801
 * Purpose:     Private function to close an error stack.
802
 *
803
 * Return:      SUCCEED/FAIL
804
 *
805
 *-------------------------------------------------------------------------
806
 */
807
static herr_t
808
H5E__close_stack(void *estack, void H5_ATTR_UNUSED **request)
809
0
{
810
0
    H5E_stack_t *estack_p = (H5E_stack_t *)estack;
811
812
0
    FUNC_ENTER_PACKAGE_NOERR
813
814
    /* Sanity check */
815
0
    assert(estack_p);
816
817
    /* Release the stack's error information */
818
0
    H5E__destroy_stack(estack_p);
819
820
    /* Free the stack structure */
821
0
    estack_p = H5FL_FREE(H5E_stack_t, estack_p);
822
823
0
    FUNC_LEAVE_NOAPI(SUCCEED)
824
0
} /* end H5E__close_stack() */
825
826
/*-------------------------------------------------------------------------
827
 * Function:    H5E__get_num
828
 *
829
 * Purpose:     Private function to retrieve number of errors in error stack.
830
 *
831
 * Return:      Success:    The number of errors
832
 *              Failure:    -1 (can't fail at this time)
833
 *
834
 *-------------------------------------------------------------------------
835
 */
836
ssize_t
837
H5E__get_num(const H5E_stack_t *estack)
838
0
{
839
0
    FUNC_ENTER_PACKAGE_NOERR
840
841
0
    assert(estack);
842
843
0
    FUNC_LEAVE_NOAPI((ssize_t)estack->nused)
844
0
} /* end H5E__get_num() */
845
846
/*-------------------------------------------------------------------------
847
 * Function:    H5E__print2
848
 *
849
 * Purpose:     Internal helper routine for H5Eprint2.
850
 *
851
 * Return:      Non-negative on success/Negative on failure
852
 *
853
 *-------------------------------------------------------------------------
854
 */
855
herr_t
856
H5E__print2(hid_t err_stack, void *_stream)
857
10
{
858
10
    H5E_stack_t *estack; /* Error stack to operate on */
859
10
    FILE        *stream    = (FILE *)_stream;
860
10
    herr_t       ret_value = SUCCEED; /* Return value */
861
862
10
    FUNC_ENTER_PACKAGE
863
864
    /* Need to check for errors */
865
10
    if (err_stack == H5E_DEFAULT) {
866
10
        if (NULL == (estack = H5E__get_my_stack()))
867
0
            HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack");
868
10
    } /* end if */
869
0
    else {
870
        /* Only clear the error stack if it's not the default stack */
871
0
        H5E_clear_stack();
872
873
0
        if (NULL == (estack = (H5E_stack_t *)H5I_object_verify(err_stack, H5I_ERROR_STACK)))
874
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a error stack ID");
875
0
    } /* end else */
876
877
    /* Print error stack */
878
10
    if (H5E__print(estack, stream, false) < 0)
879
0
        HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't display error stack");
880
881
10
done:
882
10
    FUNC_LEAVE_NOAPI(ret_value)
883
10
} /* end H5E__print2() */
884
885
/*-------------------------------------------------------------------------
886
 * Function:    H5E__append_stack
887
 *
888
 * Purpose:     Private function to append error stacks.
889
 *
890
 * Return:      Non-negative value on success/Negative on failure
891
 *
892
 *-------------------------------------------------------------------------
893
 */
894
herr_t
895
H5E__append_stack(H5E_stack_t *dst_stack, const H5E_stack_t *src_stack)
896
0
{
897
0
    unsigned u;                   /* Local index variable */
898
0
    herr_t   ret_value = SUCCEED; /* Return value */
899
900
0
    FUNC_ENTER_PACKAGE
901
902
    /* Sanity checks */
903
0
    assert(dst_stack);
904
0
    assert(src_stack);
905
906
    /* Copy the errors from the source stack to the destination stack */
907
0
    for (u = 0; u < src_stack->nused; u++) {
908
        /* Copy error stack entry */
909
0
        if (H5E__copy_stack_entry(&dst_stack->entries[dst_stack->nused], &src_stack->entries[u]) < 0)
910
0
            HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't set error entry");
911
912
        /* Increment # of errors in destination stack */
913
0
        dst_stack->nused++;
914
915
        /* Check for destination stack full */
916
0
        if (dst_stack->nused >= H5E_MAX_ENTRIES)
917
0
            break;
918
0
    } /* end for */
919
920
0
done:
921
0
    FUNC_LEAVE_NOAPI(ret_value)
922
0
} /* end H5E__append_stack() */
923
924
/*--------------------------------------------------------------------------
925
 * Function:    H5E__set_default_auto
926
 *
927
 * Purpose:     Initialize error stack to library default
928
 *
929
 * Return:      SUCCEED/FAIL
930
 *
931
 *--------------------------------------------------------------------------
932
 */
933
void
934
H5E__set_default_auto(H5E_stack_t *stk)
935
1
{
936
1
    FUNC_ENTER_PACKAGE_NOERR
937
938
    /* Initialize with default error stack */
939
1
    memcpy(stk, &H5E_err_stack_def, sizeof(H5E_err_stack_def));
940
941
1
    FUNC_LEAVE_NOAPI_VOID
942
1
} /* end H5E__set_default_auto() */
943
944
/*-------------------------------------------------------------------------
945
 * Function:    H5E__get_msg
946
 *
947
 * Purpose:     Private function to retrieve an error message.
948
 *
949
 * Return:      Success:    Message length (zero means no message)
950
 *              Failure:    -1
951
 *
952
 *-------------------------------------------------------------------------
953
 */
954
ssize_t
955
H5E__get_msg(const H5E_msg_t *msg, H5E_type_t *type, char *msg_str, size_t size)
956
0
{
957
0
    ssize_t len = -1; /* Length of error message */
958
959
0
    FUNC_ENTER_PACKAGE_NOERR
960
961
    /* Check arguments */
962
0
    assert(msg);
963
964
    /* Get the length of the message string */
965
0
    len = (ssize_t)strlen(msg->msg);
966
967
    /* Copy the message into the user's buffer, if given */
968
0
    if (msg_str) {
969
0
        strncpy(msg_str, msg->msg, size);
970
0
        if ((size_t)len >= size)
971
0
            msg_str[size - 1] = '\0';
972
0
    } /* end if */
973
974
    /* Give the message type, if asked */
975
0
    if (type)
976
0
        *type = msg->type;
977
978
    /* Set the return value to the full length of the message */
979
0
    FUNC_LEAVE_NOAPI(len)
980
0
} /* end H5E__get_msg() */
981
982
#ifndef H5_NO_DEPRECATED_SYMBOLS
983
984
/*-------------------------------------------------------------------------
985
 * Function:    H5E__walk1_cb
986
 *
987
 * Purpose:     This function is for backward compatibility.
988
 *              This is a default error stack traversal callback function
989
 *              that prints error messages to the specified output stream.
990
 *              This function is for backward compatibility with v1.6.
991
 *              It is not meant to be called directly but rather as an
992
 *              argument to the H5Ewalk() function.  This function is called
993
 *              also by H5Eprint().  Application writers are encouraged to
994
 *              use this function as a model for their own error stack
995
 *              walking functions.
996
 *
997
 *              N is a counter for how many times this function has been
998
 *              called for this particular traversal of the stack.  It always
999
 *              begins at zero for the first error on the stack (either the
1000
 *              top or bottom error, or even both, depending on the traversal
1001
 *              direction and the size of the stack).
1002
 *
1003
 *              ERR_DESC is an error description.  It contains all the
1004
 *              information about a particular error.
1005
 *
1006
 *              CLIENT_DATA is the same pointer that was passed as the
1007
 *              CLIENT_DATA argument of H5Ewalk().  It is expected to be a
1008
 *              file pointer (or stderr if null).
1009
 *
1010
 * Return:      SUCCEED/FAIL
1011
 *
1012
 *-------------------------------------------------------------------------
1013
 */
1014
static herr_t
1015
H5E__walk1_cb(int n, H5E_error1_t *err_desc, void *client_data)
1016
0
{
1017
0
    H5E_print_t     *eprint = (H5E_print_t *)client_data;
1018
0
    FILE            *stream;                             /* I/O stream to print output to */
1019
0
    const H5E_cls_t *cls_ptr;                            /* Pointer to error class */
1020
0
    H5E_msg_t       *maj_ptr;                            /* Pointer to major error info */
1021
0
    H5E_msg_t       *min_ptr;                            /* Pointer to minor error info */
1022
0
    const char      *maj_str   = "No major description"; /* Major error description */
1023
0
    const char      *min_str   = "No minor description"; /* Minor error description */
1024
0
    bool             have_desc = true; /* Flag to indicate whether the error has a "real" description */
1025
#ifdef H5_HAVE_THREADSAFE_API
1026
    uint64_t thread_id = 0; /* ID of thread */
1027
#endif
1028
0
    herr_t ret_value = SUCCEED;
1029
1030
0
    FUNC_ENTER_PACKAGE_NOERR
1031
1032
    /* Check arguments */
1033
0
    assert(err_desc);
1034
1035
    /* If no client data was passed, output to stderr */
1036
0
    if (!client_data)
1037
0
        stream = stderr;
1038
0
    else
1039
0
        stream = eprint->stream;
1040
1041
    /* Get descriptions for the major and minor error numbers */
1042
0
    maj_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->maj_num, H5I_ERROR_MSG);
1043
0
    min_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->min_num, H5I_ERROR_MSG);
1044
1045
    /* Check for bad pointer(s), but can't issue error, just leave */
1046
0
    if (!maj_ptr || !min_ptr)
1047
0
        HGOTO_DONE(FAIL);
1048
1049
0
    if (maj_ptr->msg)
1050
0
        maj_str = maj_ptr->msg;
1051
0
    if (min_ptr->msg)
1052
0
        min_str = min_ptr->msg;
1053
1054
    /* Get error class info */
1055
0
    cls_ptr = maj_ptr->cls;
1056
1057
#ifdef H5_HAVE_THREADSAFE_API
1058
    if (H5TS_thread_id(&thread_id) < 0)
1059
        HGOTO_DONE(FAIL);
1060
#endif
1061
1062
    /* Print error class header if new class */
1063
0
    if (eprint->cls.lib_name == NULL || strcmp(cls_ptr->lib_name, eprint->cls.lib_name) != 0) {
1064
        /* update to the new class information */
1065
0
        if (cls_ptr->cls_name)
1066
0
            eprint->cls.cls_name = cls_ptr->cls_name;
1067
0
        if (cls_ptr->lib_name)
1068
0
            eprint->cls.lib_name = cls_ptr->lib_name;
1069
0
        if (cls_ptr->lib_vers)
1070
0
            eprint->cls.lib_vers = cls_ptr->lib_vers;
1071
1072
0
        fprintf(stream, "%s-DIAG: Error detected in %s (%s)",
1073
0
                (cls_ptr->cls_name ? cls_ptr->cls_name : "(null)"),
1074
0
                (cls_ptr->lib_name ? cls_ptr->lib_name : "(null)"),
1075
0
                (cls_ptr->lib_vers ? cls_ptr->lib_vers : "(null)"));
1076
1077
        /* try show the process or thread id in multiple processes cases*/
1078
#ifdef H5_HAVE_PARALLEL
1079
        {
1080
            int mpi_rank, mpi_initialized, mpi_finalized;
1081
1082
            MPI_Initialized(&mpi_initialized);
1083
            MPI_Finalized(&mpi_finalized);
1084
1085
            if (mpi_initialized && !mpi_finalized) {
1086
                MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
1087
                fprintf(stream, " MPI-process %d", mpi_rank);
1088
            } /* end if */
1089
#ifdef H5_HAVE_THREADSAFE_API
1090
            else
1091
                fprintf(stream, " thread %" PRIu64, thread_id);
1092
#endif
1093
        } /* end block */
1094
#else
1095
#ifdef H5_HAVE_THREADSAFE_API
1096
        fprintf(stream, " thread %" PRIu64, thread_id);
1097
#endif
1098
0
#endif
1099
0
        fprintf(stream, ":\n");
1100
0
    } /* end if */
1101
1102
    /* Check for "real" error description - used to format output more nicely */
1103
0
    if (err_desc->desc == NULL || strlen(err_desc->desc) == 0)
1104
0
        have_desc = false;
1105
1106
    /* Print error message */
1107
0
    fprintf(stream, "%*s#%03d: %s line %u in %s()%s%s\n", H5E_INDENT, "", n, err_desc->file_name,
1108
0
            err_desc->line, err_desc->func_name, (have_desc ? ": " : ""), (have_desc ? err_desc->desc : ""));
1109
0
    fprintf(stream, "%*smajor: %s\n", (H5E_INDENT * 2), "", maj_str);
1110
0
    fprintf(stream, "%*sminor: %s\n", (H5E_INDENT * 2), "", min_str);
1111
1112
0
done:
1113
0
    FUNC_LEAVE_NOAPI(ret_value)
1114
0
} /* end H5E__walk1_cb() */
1115
#endif /* H5_NO_DEPRECATED_SYMBOLS */
1116
1117
/*-------------------------------------------------------------------------
1118
 * Function:    H5E__walk2_cb
1119
 *
1120
 * Purpose:     This is a default error stack traversal callback function
1121
 *              that prints error messages to the specified output stream.
1122
 *              It is not meant to be called directly but rather as an
1123
 *              argument to the H5Ewalk2() function.  This function is
1124
 *              called also by H5Eprint2().  Application writers are
1125
 *              encouraged to use this function as a model for their own
1126
 *              error stack walking functions.
1127
 *
1128
 *              N is a counter for how many times this function has been
1129
 *              called for this particular traversal of the stack.  It always
1130
 *              begins at zero for the first error on the stack (either the
1131
 *              top or bottom error, or even both, depending on the traversal
1132
 *              direction and the size of the stack).
1133
 *
1134
 *              ERR_DESC is an error description.  It contains all the
1135
 *              information about a particular error.
1136
 *
1137
 *              CLIENT_DATA is the same pointer that was passed as the
1138
 *              CLIENT_DATA argument of H5Ewalk().  It is expected to be a
1139
 *              file pointer (or stderr if null).
1140
 *
1141
 * Return:      SUCCEED/FAIL
1142
 *
1143
 *-------------------------------------------------------------------------
1144
 */
1145
static herr_t
1146
H5E__walk2_cb(unsigned n, const H5E_error2_t *err_desc, void *client_data)
1147
82
{
1148
82
    H5E_print_t *eprint = (H5E_print_t *)client_data;
1149
82
    FILE        *stream;                             /* I/O stream to print output to */
1150
82
    H5E_cls_t   *cls_ptr;                            /* Pointer to error class */
1151
82
    H5E_msg_t   *maj_ptr;                            /* Pointer to major error info */
1152
82
    H5E_msg_t   *min_ptr;                            /* Pointer to minor error info */
1153
82
    const char  *maj_str   = "No major description"; /* Major error description */
1154
82
    const char  *min_str   = "No minor description"; /* Minor error description */
1155
82
    bool         have_desc = true; /* Flag to indicate whether the error has a "real" description */
1156
#ifdef H5_HAVE_THREADSAFE_API
1157
    uint64_t thread_id = 0; /* ID of thread */
1158
#endif
1159
82
    herr_t ret_value = SUCCEED;
1160
1161
82
    FUNC_ENTER_PACKAGE_NOERR
1162
1163
    /* Check arguments */
1164
82
    assert(err_desc);
1165
1166
    /* If no client data was passed, output to stderr */
1167
82
    if (!client_data)
1168
0
        stream = stderr;
1169
82
    else
1170
82
        stream = eprint->stream;
1171
1172
    /* Get descriptions for the major and minor error numbers */
1173
82
    maj_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->maj_num, H5I_ERROR_MSG);
1174
82
    min_ptr = (H5E_msg_t *)H5I_object_verify(err_desc->min_num, H5I_ERROR_MSG);
1175
1176
    /* Check for bad pointer(s), but can't issue error, just leave */
1177
82
    if (!maj_ptr || !min_ptr)
1178
0
        HGOTO_DONE(FAIL);
1179
1180
82
    if (maj_ptr->msg)
1181
82
        maj_str = maj_ptr->msg;
1182
82
    if (min_ptr->msg)
1183
82
        min_str = min_ptr->msg;
1184
1185
    /* Get error class info.  Don't use the class of the major or minor error because
1186
     * they might be different. */
1187
82
    cls_ptr = (H5E_cls_t *)H5I_object_verify(err_desc->cls_id, H5I_ERROR_CLASS);
1188
1189
    /* Check for bad pointer(s), but can't issue error, just leave */
1190
82
    if (!cls_ptr)
1191
0
        HGOTO_DONE(FAIL);
1192
1193
#ifdef H5_HAVE_THREADSAFE_API
1194
    if (H5TS_thread_id(&thread_id) < 0)
1195
        HGOTO_DONE(FAIL);
1196
#endif
1197
1198
    /* Print error class header if new class */
1199
82
    if (eprint->cls.lib_name == NULL || strcmp(cls_ptr->lib_name, eprint->cls.lib_name) != 0) {
1200
        /* update to the new class information */
1201
10
        if (cls_ptr->cls_name)
1202
10
            eprint->cls.cls_name = cls_ptr->cls_name;
1203
10
        if (cls_ptr->lib_name)
1204
10
            eprint->cls.lib_name = cls_ptr->lib_name;
1205
10
        if (cls_ptr->lib_vers)
1206
10
            eprint->cls.lib_vers = cls_ptr->lib_vers;
1207
1208
10
        fprintf(stream, "%s-DIAG: Error detected in %s (%s)",
1209
10
                (cls_ptr->cls_name ? cls_ptr->cls_name : "(null)"),
1210
10
                (cls_ptr->lib_name ? cls_ptr->lib_name : "(null)"),
1211
10
                (cls_ptr->lib_vers ? cls_ptr->lib_vers : "(null)"));
1212
1213
        /* try show the process or thread id in multiple processes cases*/
1214
#ifdef H5_HAVE_PARALLEL
1215
        {
1216
            int mpi_rank, mpi_initialized, mpi_finalized;
1217
1218
            MPI_Initialized(&mpi_initialized);
1219
            MPI_Finalized(&mpi_finalized);
1220
1221
            if (mpi_initialized && !mpi_finalized) {
1222
                MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
1223
                fprintf(stream, " MPI-process %d", mpi_rank);
1224
            } /* end if */
1225
#ifdef H5_HAVE_THREADSAFE_API
1226
            else
1227
                fprintf(stream, " thread %" PRIu64, thread_id);
1228
#endif
1229
        } /* end block */
1230
#else
1231
#ifdef H5_HAVE_THREADSAFE_API
1232
        fprintf(stream, " thread %" PRIu64, thread_id);
1233
#endif
1234
10
#endif
1235
10
        fprintf(stream, ":\n");
1236
10
    } /* end if */
1237
1238
    /* Check for "real" error description - used to format output more nicely */
1239
82
    if (err_desc->desc == NULL || strlen(err_desc->desc) == 0)
1240
0
        have_desc = false;
1241
1242
    /* Print error message */
1243
82
    fprintf(stream, "%*s#%03u: %s line %u in %s()%s%s\n", H5E_INDENT, "", n, err_desc->file_name,
1244
82
            err_desc->line, err_desc->func_name, (have_desc ? ": " : ""), (have_desc ? err_desc->desc : ""));
1245
82
    fprintf(stream, "%*smajor: %s\n", (H5E_INDENT * 2), "", maj_str);
1246
82
    fprintf(stream, "%*sminor: %s\n", (H5E_INDENT * 2), "", min_str);
1247
1248
82
done:
1249
82
    FUNC_LEAVE_NOAPI(ret_value)
1250
82
} /* end H5E__walk2_cb() */
1251
1252
/*-------------------------------------------------------------------------
1253
 * Function:    H5E__print
1254
 *
1255
 * Purpose:     Private function to print the error stack in some default
1256
 *              way.  This is just a convenience function for H5Ewalk() and
1257
 *              H5Ewalk2() with a function that prints error messages.
1258
 *              Users are encouraged to write their own more specific error
1259
 *              handlers.
1260
 *
1261
 * Return:      SUCCEED/FAIL
1262
 *
1263
 *-------------------------------------------------------------------------
1264
 */
1265
herr_t
1266
H5E__print(const H5E_stack_t *estack, FILE *stream, bool bk_compatible)
1267
10
{
1268
10
    H5E_print_t   eprint;  /* Callback information to pass to H5E_walk() */
1269
10
    H5E_walk_op_t walk_op; /* Error stack walking callback */
1270
10
    herr_t        ret_value = SUCCEED;
1271
1272
10
    FUNC_ENTER_PACKAGE
1273
1274
    /* Sanity check */
1275
10
    assert(estack);
1276
1277
    /* If no stream was given, use stderr */
1278
10
    if (!stream)
1279
10
        eprint.stream = stderr;
1280
0
    else
1281
0
        eprint.stream = stream;
1282
1283
    /* Reset the original error class information */
1284
10
    memset(&eprint.cls, 0, sizeof(H5E_cls_t));
1285
1286
    /* Walk the error stack */
1287
10
    if (bk_compatible) {
1288
0
#ifndef H5_NO_DEPRECATED_SYMBOLS
1289
0
        walk_op.vers    = 1;
1290
0
        walk_op.u.func1 = H5E__walk1_cb;
1291
0
        if (H5E__walk(estack, H5E_WALK_DOWNWARD, &walk_op, (void *)&eprint) < 0)
1292
0
            HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack");
1293
#else  /* H5_NO_DEPRECATED_SYMBOLS */
1294
        assert(0 && "version 1 error stack print without deprecated symbols!");
1295
#endif /* H5_NO_DEPRECATED_SYMBOLS */
1296
0
    }  /* end if */
1297
10
    else {
1298
10
        walk_op.vers    = 2;
1299
10
        walk_op.u.func2 = H5E__walk2_cb;
1300
10
        if (H5E__walk(estack, H5E_WALK_DOWNWARD, &walk_op, (void *)&eprint) < 0)
1301
0
            HGOTO_ERROR(H5E_ERROR, H5E_CANTLIST, FAIL, "can't walk error stack");
1302
10
    } /* end else */
1303
1304
10
done:
1305
10
    FUNC_LEAVE_NOAPI(ret_value)
1306
10
} /* end H5E__print() */
1307
1308
/*-------------------------------------------------------------------------
1309
 * Function:    H5E__walk
1310
 *
1311
 * Purpose:     Private function for H5Ewalk.
1312
 *              Walks the error stack, calling the specified function for
1313
 *              each error on the stack.  The DIRECTION argument determines
1314
 *              whether the stack is walked from the inside out or the
1315
 *              outside in.  The value H5E_WALK_UPWARD means begin with the
1316
 *              most specific error and end at the API; H5E_WALK_DOWNWARD
1317
 *              means to start at the API and end at the inner-most function
1318
 *              where the error was first detected.
1319
 *
1320
 *              The function pointed to by STACK_FUNC will be called for
1321
 *              each error record in the error stack. It's arguments will
1322
 *              include an index number (beginning at zero regardless of
1323
 *              stack traversal direction), an error stack entry, and the
1324
 *              CLIENT_DATA pointer passed to H5E_print.
1325
 *
1326
 *              The function FUNC is also provided for backward compatibility.
1327
 *              When BK_COMPATIBLE is set to be true, FUNC is used to be
1328
 *              compatible with older library.  If BK_COMPATIBLE is false,
1329
 *              STACK_FUNC is used.
1330
 *
1331
 * Return:      SUCCEED/FAIL
1332
 *
1333
 *-------------------------------------------------------------------------
1334
 */
1335
herr_t
1336
H5E__walk(const H5E_stack_t *estack, H5E_direction_t direction, const H5E_walk_op_t *op, void *client_data)
1337
10
{
1338
10
    int    i;                        /* Local index variable */
1339
10
    herr_t ret_value = H5_ITER_CONT; /* Return value */
1340
1341
10
    FUNC_ENTER_PACKAGE_NOERR
1342
1343
    /* Sanity check */
1344
10
    assert(estack);
1345
10
    assert(op);
1346
1347
    /* check args, but rather than failing use some default value */
1348
10
    if (direction != H5E_WALK_UPWARD && direction != H5E_WALK_DOWNWARD)
1349
0
        direction = H5E_WALK_UPWARD;
1350
1351
    /* Walk the stack if a callback function was given */
1352
10
    if (op->vers == 1) {
1353
0
#ifndef H5_NO_DEPRECATED_SYMBOLS
1354
0
        if (op->u.func1) {
1355
0
            H5E_error1_t old_err;
1356
1357
0
            ret_value = SUCCEED;
1358
0
            if (H5E_WALK_UPWARD == direction) {
1359
0
                for (i = 0; i < (int)estack->nused && ret_value == H5_ITER_CONT; i++) {
1360
                    /* Point to each error record on the stack and pass it to callback function.*/
1361
0
                    old_err.maj_num   = estack->entries[i].err.maj_num;
1362
0
                    old_err.min_num   = estack->entries[i].err.min_num;
1363
0
                    old_err.file_name = estack->entries[i].err.file_name;
1364
0
                    old_err.func_name = estack->entries[i].err.func_name;
1365
0
                    old_err.line      = estack->entries[i].err.line;
1366
0
                    old_err.desc      = estack->entries[i].err.desc;
1367
1368
                    /* Prepare & restore library for user callback */
1369
0
                    H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR)
1370
0
                        {
1371
0
                            ret_value = (op->u.func1)(i, &old_err, client_data);
1372
0
                        }
1373
0
                    H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR)
1374
0
                } /* end for */
1375
0
            }     /* end if */
1376
0
            else {
1377
0
                H5_CHECK_OVERFLOW(estack->nused - 1, size_t, int);
1378
0
                for (i = (int)(estack->nused - 1); i >= 0 && ret_value == H5_ITER_CONT; i--) {
1379
                    /* Point to each error record on the stack and pass it to callback function.*/
1380
0
                    old_err.maj_num   = estack->entries[i].err.maj_num;
1381
0
                    old_err.min_num   = estack->entries[i].err.min_num;
1382
0
                    old_err.file_name = estack->entries[i].err.file_name;
1383
0
                    old_err.func_name = estack->entries[i].err.func_name;
1384
0
                    old_err.line      = estack->entries[i].err.line;
1385
0
                    old_err.desc      = estack->entries[i].err.desc;
1386
1387
                    /* Prepare & restore library for user callback */
1388
0
                    H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR)
1389
0
                        {
1390
0
                            ret_value =
1391
0
                                (op->u.func1)((int)(estack->nused - (size_t)(i + 1)), &old_err, client_data);
1392
0
                        }
1393
0
                    H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR)
1394
0
                } /* end for */
1395
0
            }     /* end else */
1396
1397
0
            if (ret_value < 0)
1398
0
                HERROR(H5E_ERROR, H5E_CANTLIST, "can't walk error stack");
1399
0
        } /* end if */
1400
#else     /* H5_NO_DEPRECATED_SYMBOLS */
1401
        assert(0 && "version 1 error stack walk without deprecated symbols!");
1402
#endif    /* H5_NO_DEPRECATED_SYMBOLS */
1403
0
    }     /* end if */
1404
10
    else {
1405
10
        assert(op->vers == 2);
1406
10
        if (op->u.func2) {
1407
10
            ret_value = SUCCEED;
1408
10
            if (H5E_WALK_UPWARD == direction) {
1409
0
                for (i = 0; i < (int)estack->nused && ret_value == H5_ITER_CONT; i++) {
1410
                    /* Prepare & restore library for user callback */
1411
0
                    H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR)
1412
0
                        {
1413
0
                            ret_value = (op->u.func2)((unsigned)i, &estack->entries[i].err, client_data);
1414
0
                        }
1415
0
                    H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR)
1416
0
                }
1417
0
            } /* end if */
1418
10
            else {
1419
10
                H5_CHECK_OVERFLOW(estack->nused - 1, size_t, int);
1420
92
                for (i = (int)(estack->nused - 1); i >= 0 && ret_value == H5_ITER_CONT; i--) {
1421
                    /* Prepare & restore library for user callback */
1422
82
                    H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR)
1423
82
                        {
1424
82
                            ret_value = (op->u.func2)((unsigned)(estack->nused - (size_t)(i + 1)),
1425
82
                                                      &estack->entries[i].err, client_data);
1426
82
                        }
1427
82
                    H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR)
1428
82
                }
1429
10
            } /* end else */
1430
1431
10
            if (ret_value < 0)
1432
0
                HERROR(H5E_ERROR, H5E_CANTLIST, "can't walk error stack");
1433
10
        } /* end if */
1434
10
    }     /* end else */
1435
1436
10
    FUNC_LEAVE_NOAPI(ret_value)
1437
10
} /* end H5E__walk() */
1438
1439
/*-------------------------------------------------------------------------
1440
 * Function:    H5E__get_auto
1441
 *
1442
 * Purpose:     Private function to return the current settings for the
1443
 *              automatic error stack traversal function and its data
1444
 *              for specific error stack. Either (or both) arguments may
1445
 *              be null in which case the value is not returned.
1446
 *
1447
 * Return:      SUCCEED/FAIL
1448
 *
1449
 *-------------------------------------------------------------------------
1450
 */
1451
herr_t
1452
H5E__get_auto(const H5E_stack_t *estack, H5E_auto_op_t *op, void **client_data)
1453
1
{
1454
1
    FUNC_ENTER_PACKAGE_NOERR
1455
1456
1
    assert(estack);
1457
1458
    /* Retrieve the requested information */
1459
1
    if (op)
1460
1
        *op = estack->auto_op;
1461
1
    if (client_data)
1462
0
        *client_data = estack->auto_data;
1463
1464
1
    FUNC_LEAVE_NOAPI(SUCCEED)
1465
1
} /* end H5E__get_auto() */
1466
1467
/*-------------------------------------------------------------------------
1468
 * Function:    H5E_get_default_auto_func
1469
 *
1470
 * Purpose:     Private function to retrieve the default error stack's
1471
 *              reporting function.
1472
 *
1473
 * Return:      SUCCEED/FAIL
1474
 *
1475
 *-------------------------------------------------------------------------
1476
 */
1477
herr_t
1478
H5E_get_default_auto_func(H5E_auto2_t *func)
1479
1
{
1480
1
    H5E_stack_t  *estack;              /* Error stack to operate on */
1481
1
    H5E_auto_op_t op;                  /* Error stack function */
1482
1
    herr_t        ret_value = SUCCEED; /* Return value */
1483
1484
1
    FUNC_ENTER_NOAPI(FAIL)
1485
1486
    /* Retrieve default error stack */
1487
1
    if (NULL == (estack = H5E__get_my_stack()))
1488
0
        HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack");
1489
1490
    /* Get the automatic error reporting information */
1491
1
    if (H5E__get_auto(estack, &op, NULL) < 0)
1492
0
        HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get automatic error info");
1493
1494
    /* Retrieve error output function */
1495
1
    *func = op.func2;
1496
1497
1
done:
1498
1
    FUNC_LEAVE_NOAPI(ret_value)
1499
1
} /* end H5E_get_default_auto_func() */
1500
1501
/*-------------------------------------------------------------------------
1502
 * Function:    H5E__set_auto
1503
 *
1504
 * Purpose:     Private function to turn on or off automatic printing of
1505
 *              errors for certain error stack.  When turned on (non-null
1506
 *              FUNC pointer) any API function which returns an error
1507
 *              indication will first call FUNC passing it CLIENT_DATA
1508
 *              as an argument.
1509
 *
1510
 *              The default values before this function is called are
1511
 *              H5Eprint2() with client data being the standard error stream,
1512
 *              stderr.
1513
 *
1514
 *              Automatic stack traversal is always in the H5E_WALK_DOWNWARD
1515
 *              direction.
1516
 *
1517
 * Return:      SUCCEED/FAIL
1518
 *
1519
 *-------------------------------------------------------------------------
1520
 */
1521
herr_t
1522
H5E__set_auto(H5E_stack_t *estack, const H5E_auto_op_t *op, void *client_data)
1523
0
{
1524
0
    FUNC_ENTER_PACKAGE_NOERR
1525
1526
0
    assert(estack);
1527
1528
    /* Set the automatic error reporting info */
1529
0
    estack->auto_op   = *op;
1530
0
    estack->auto_data = client_data;
1531
1532
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1533
0
} /* end H5E__set_auto() */
1534
1535
/*-------------------------------------------------------------------------
1536
 * Function:    H5E_printf_stack
1537
 *
1538
 * Purpose:     Printf-like wrapper around H5E__push_stack.
1539
 *
1540
 * Return:      SUCCEED/FAIL
1541
 *
1542
 *-------------------------------------------------------------------------
1543
 */
1544
herr_t
1545
H5E_printf_stack(const char *file, const char *func, unsigned line, hid_t maj_id, hid_t min_id,
1546
                 const char *fmt, ...)
1547
82
{
1548
82
    H5E_stack_t *estack;               /* Pointer to error stack to modify */
1549
82
    va_list      ap;                   /* Varargs info */
1550
82
    bool         va_started = false;   /* Whether the variable argument list is open */
1551
82
    herr_t       ret_value  = SUCCEED; /* Return value */
1552
1553
    /*
1554
     * WARNING: We cannot call HERROR() from within this function or else we
1555
     *    could enter infinite recursion.  Furthermore, we also cannot
1556
     *    call any other HDF5 macro or function which might call
1557
     *    HERROR().  HERROR() is called by HRETURN_ERROR() which could
1558
     *    be called by FUNC_ENTER().
1559
     */
1560
82
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1561
1562
    /* Sanity check */
1563
82
    assert(maj_id >= H5E_first_maj_id_g && maj_id <= H5E_last_maj_id_g);
1564
82
    assert(min_id >= H5E_first_min_id_g && min_id <= H5E_last_min_id_g);
1565
82
    assert(fmt);
1566
1567
    /* Get the 'default' error stack */
1568
82
    if (NULL == (estack = H5E__get_my_stack()))
1569
0
        HGOTO_DONE(FAIL);
1570
1571
    /* Check if error reporting is paused for this stack */
1572
82
    if (!estack->paused) {
1573
        /* Start the variable-argument parsing */
1574
82
        va_start(ap, fmt);
1575
82
        va_started = true;
1576
1577
        /* Push the error on the stack */
1578
82
        if (H5E__push_stack(estack, false, file, func, line, H5E_ERR_CLS_g, maj_id, min_id, fmt, &ap) < 0)
1579
0
            HGOTO_DONE(FAIL);
1580
82
    }
1581
1582
82
done:
1583
82
    if (va_started)
1584
82
        va_end(ap);
1585
1586
82
    FUNC_LEAVE_NOAPI(ret_value)
1587
82
} /* end H5E_printf_stack() */
1588
1589
/*-------------------------------------------------------------------------
1590
 * Function:    H5E__push_stack
1591
 *
1592
 * Purpose:     Pushes a new error record onto error stack for the current
1593
 *              thread.  The error has major and minor IDs MAJ_ID and
1594
 *              MIN_ID, the name of a function where the error was detected,
1595
 *              the name of the file where the error was detected, the
1596
 *              line within that file, and an error description string.  The
1597
 *              function name, file name, and error description strings must
1598
 *              be statically allocated (the FUNC_ENTER() macro takes care of
1599
 *              the function name and file name automatically, but the
1600
 *              programmer is responsible for the description string).
1601
 *
1602
 * Return:      SUCCEED/FAIL
1603
 *
1604
 *-------------------------------------------------------------------------
1605
 */
1606
herr_t
1607
H5E__push_stack(H5E_stack_t *estack, bool app_entry, const char *file, const char *func, unsigned line,
1608
                hid_t cls_id, hid_t maj_id, hid_t min_id, const char *fmt, va_list *ap)
1609
82
{
1610
82
    herr_t ret_value = SUCCEED; /* Return value */
1611
1612
    /*
1613
     * WARNING: We cannot call HERROR() from within this function or else we
1614
     *    could enter infinite recursion.  Furthermore, we also cannot
1615
     *    call any other HDF5 macro or function which might call
1616
     *    HERROR().  HERROR() is called by HRETURN_ERROR() which could
1617
     *    be called by FUNC_ENTER().
1618
     */
1619
82
    FUNC_ENTER_PACKAGE_NOERR
1620
1621
    /* Sanity check */
1622
82
    assert(cls_id > 0);
1623
82
    assert(maj_id > 0);
1624
82
    assert(min_id > 0);
1625
1626
    /*
1627
     * Push the error if there's room.  Otherwise just forget it.
1628
     */
1629
82
    if (estack->nused < H5E_MAX_ENTRIES) {
1630
82
        estack->entries[estack->nused].app_entry = app_entry;
1631
82
        if (H5E__set_stack_entry(&estack->entries[estack->nused].err, file, func, line, cls_id, maj_id,
1632
82
                                 min_id, fmt, ap) < 0)
1633
0
            HGOTO_DONE(FAIL);
1634
82
        estack->nused++;
1635
82
    } /* end if */
1636
1637
82
done:
1638
82
    FUNC_LEAVE_NOAPI(ret_value)
1639
82
} /* end H5E__push_stack() */
1640
1641
/*-------------------------------------------------------------------------
1642
 * Function:    H5E__copy_stack_entry
1643
 *
1644
 * Purpose:     Copy a stack entry
1645
 *
1646
 * Return:      SUCCEED/FAIL
1647
 *
1648
 *-------------------------------------------------------------------------
1649
 */
1650
static herr_t
1651
H5E__copy_stack_entry(H5E_entry_t *dst_entry, const H5E_entry_t *src_entry)
1652
0
{
1653
0
    herr_t ret_value = SUCCEED; /* Return value */
1654
1655
0
    FUNC_ENTER_PACKAGE
1656
1657
    /* Sanity check */
1658
0
    assert(dst_entry);
1659
0
    assert(src_entry);
1660
1661
    /* Shallow copy all fields */
1662
0
    *dst_entry = *src_entry;
1663
1664
    /* Deep copy application entries */
1665
0
    if (dst_entry->app_entry) {
1666
        /* Note: don't waste time incrementing library internal error IDs */
1667
0
        if (dst_entry->err.cls_id != H5E_ERR_CLS_g)
1668
0
            if (H5I_inc_ref(dst_entry->err.cls_id, false) < 0)
1669
0
                HGOTO_ERROR(H5E_ERROR, H5E_CANTINC, FAIL, "unable to increment ref count on error class");
1670
0
        if (dst_entry->err.maj_num < H5E_first_maj_id_g || dst_entry->err.maj_num > H5E_last_maj_id_g)
1671
0
            if (H5I_inc_ref(dst_entry->err.maj_num, false) < 0)
1672
0
                HGOTO_ERROR(H5E_ERROR, H5E_CANTINC, FAIL, "unable to increment ref count on error message");
1673
0
        if (dst_entry->err.min_num < H5E_first_min_id_g || dst_entry->err.min_num > H5E_last_min_id_g)
1674
0
            if (H5I_inc_ref(dst_entry->err.min_num, false) < 0)
1675
0
                HGOTO_ERROR(H5E_ERROR, H5E_CANTINC, FAIL, "unable to increment ref count on error message");
1676
        /* The library's 'func' & 'file' strings are statically allocated (by the compiler)
1677
         * there's no need to duplicate them.
1678
         */
1679
0
        if (NULL == (dst_entry->err.file_name = strdup(src_entry->err.file_name)))
1680
0
            HGOTO_ERROR(H5E_ERROR, H5E_CANTCOPY, FAIL, "unable to duplicate file name");
1681
0
        if (NULL == (dst_entry->err.func_name = strdup(src_entry->err.func_name)))
1682
0
            HGOTO_ERROR(H5E_ERROR, H5E_CANTCOPY, FAIL, "unable to duplicate function name");
1683
0
    }
1684
0
    if (NULL == (dst_entry->err.desc = strdup(src_entry->err.desc)))
1685
0
        HGOTO_ERROR(H5E_ERROR, H5E_CANTCOPY, FAIL, "unable to duplicate error description");
1686
1687
0
done:
1688
0
    FUNC_LEAVE_NOAPI(ret_value)
1689
0
} /* end H5E__copy_stack_entry() */
1690
1691
/*-------------------------------------------------------------------------
1692
 * Function:    H5E__set_stack_entry
1693
 *
1694
 * Purpose:     Sets the information for a given stack entry.
1695
 *
1696
 * Return:      SUCCEED/FAIL
1697
 *
1698
 *-------------------------------------------------------------------------
1699
 */
1700
static herr_t
1701
H5E__set_stack_entry(H5E_error2_t *err_entry, const char *file, const char *func, unsigned line, hid_t cls_id,
1702
                     hid_t maj_id, hid_t min_id, const char *fmt, va_list *ap)
1703
82
{
1704
82
    herr_t ret_value = SUCCEED; /* Return value */
1705
1706
    /*
1707
     * WARNING: We cannot call HERROR() from within this function or else we
1708
     *    could enter infinite recursion.  Furthermore, we also cannot
1709
     *    call any other HDF5 macro or function which might call
1710
     *    HERROR().  HERROR() is called by HRETURN_ERROR() which could
1711
     *    be called by FUNC_ENTER().
1712
     */
1713
82
    FUNC_ENTER_PACKAGE_NOERR
1714
1715
    /* Sanity check */
1716
82
    assert(err_entry);
1717
82
    assert(cls_id > 0);
1718
82
    assert(maj_id > 0);
1719
82
    assert(min_id > 0);
1720
1721
    /*
1722
     * Don't fail if arguments are bad.  Instead, substitute some default
1723
     * value.
1724
     */
1725
82
    if (!func)
1726
0
        func = "Unknown_Function";
1727
82
    if (!file)
1728
0
        file = "Unknown_File";
1729
82
    if (!fmt)
1730
0
        fmt = "No description given";
1731
1732
    /* Set the entry fields */
1733
    /* NOTE: non-library IDs have already been incremented */
1734
82
    err_entry->cls_id  = cls_id;
1735
82
    err_entry->maj_num = maj_id;
1736
82
    err_entry->min_num = min_id;
1737
    /* The 'func' & 'file' strings are either statically allocated (by the
1738
     * compiler), for internal error messages, or have already been duplicated,
1739
     * for application errors, so there's no need to duplicate them here.
1740
     */
1741
82
    err_entry->func_name = func;
1742
82
    err_entry->file_name = file;
1743
82
    err_entry->line      = line;
1744
82
    if (ap) {
1745
82
        char *desc = NULL;
1746
1747
82
        H5_WARN_FORMAT_NONLITERAL_OFF
1748
82
        if (HDvasprintf(&desc, fmt, *ap) < 0)
1749
0
            HGOTO_DONE(FAIL);
1750
82
        H5_WARN_FORMAT_NONLITERAL_ON
1751
1752
82
        err_entry->desc = desc;
1753
82
    }
1754
0
    else {
1755
0
        if (NULL == (err_entry->desc = strdup(fmt)))
1756
0
            HGOTO_DONE(FAIL);
1757
0
    }
1758
1759
82
done:
1760
82
    FUNC_LEAVE_NOAPI(ret_value)
1761
82
} /* end H5E__set_stack_entry() */
1762
1763
/*-------------------------------------------------------------------------
1764
 * Function:    H5E__clear_entries
1765
 *
1766
 * Purpose:     Private function to clear the error stack entries for the
1767
 *              specified error stack.
1768
 *
1769
 * Return:      SUCCEED/FAIL
1770
 *
1771
 *-------------------------------------------------------------------------
1772
 */
1773
static herr_t
1774
H5E__clear_entries(H5E_stack_t *estack, size_t nentries)
1775
10
{
1776
10
    unsigned u;                   /* Local index variable */
1777
10
    herr_t   ret_value = SUCCEED; /* Return value */
1778
1779
10
    FUNC_ENTER_PACKAGE
1780
1781
    /* Sanity check */
1782
10
    assert(estack);
1783
10
    assert(estack->nused >= nentries);
1784
1785
    /* Empty the error stack from the top down */
1786
92
    for (u = 0; nentries > 0; nentries--, u++) {
1787
82
        H5E_entry_t *error; /* Pointer to error stack entry to clear */
1788
1789
82
        error = &(estack->entries[estack->nused - (u + 1)]);
1790
1791
        /* Decrement the IDs to indicate that they are no longer used by this stack */
1792
        /* (In reverse order that they were incremented, so that reference counts work well) */
1793
        /* Note: don't decrement library internal error IDs, since they weren't incremented */
1794
82
        if (error->err.min_num < H5E_first_min_id_g || error->err.min_num > H5E_last_min_id_g)
1795
0
            if (H5I_dec_ref(error->err.min_num) < 0)
1796
0
                HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error message");
1797
82
        if (error->err.maj_num < H5E_first_maj_id_g || error->err.maj_num > H5E_last_maj_id_g)
1798
0
            if (H5I_dec_ref(error->err.maj_num) < 0)
1799
0
                HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error message");
1800
82
        if (error->err.cls_id != H5E_ERR_CLS_g)
1801
0
            if (H5I_dec_ref(error->err.cls_id) < 0)
1802
0
                HGOTO_ERROR(H5E_ERROR, H5E_CANTDEC, FAIL, "unable to decrement ref count on error class");
1803
1804
        /* Release strings */
1805
        /* The library's 'func' & 'file' strings are statically allocated (by the
1806
         * compiler) and are not allocated, so there's no need to free them.
1807
         */
1808
82
        if (error->app_entry) {
1809
0
            H5MM_xfree_const(error->err.file_name);
1810
0
            H5MM_xfree_const(error->err.func_name);
1811
0
        }
1812
82
        error->err.file_name = NULL;
1813
82
        error->err.func_name = NULL;
1814
82
        error->err.desc      = (const char *)H5MM_xfree_const(error->err.desc);
1815
82
    }
1816
1817
    /* Decrement number of errors on stack */
1818
10
    estack->nused -= u;
1819
1820
10
done:
1821
10
    FUNC_LEAVE_NOAPI(ret_value)
1822
10
} /* end H5E__clear_entries() */
1823
1824
/*-------------------------------------------------------------------------
1825
 * Function:    H5E_clear_stack
1826
 *
1827
 * Purpose:     Clear the default error stack
1828
 *
1829
 * Note:        This routine should _not_ be used inside general library
1830
 *              code in general.  It creates complex locking issues for
1831
 *              threadsafe code.  Generally, using a 'try' parameter or
1832
 *              an 'exists' parameter should be used if an operation is
1833
 *              being used to probe for information.  Remember: failing
1834
 *              to locate a record is not an error for a data structure,
1835
 *              although it could be an error for the user of the data
1836
 *              structure.
1837
 *
1838
 * Return:      SUCCEED/FAIL
1839
 *
1840
 *-------------------------------------------------------------------------
1841
 */
1842
herr_t
1843
H5E_clear_stack(void)
1844
11
{
1845
11
    H5E_stack_t *estack;              /* Error stack to clear */
1846
11
    herr_t       ret_value = SUCCEED; /* Return value */
1847
1848
11
    FUNC_ENTER_NOAPI(FAIL)
1849
1850
    /* Get 'default' error stack */
1851
11
    if (NULL == (estack = H5E__get_my_stack()))
1852
0
        HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack");
1853
1854
    /* Empty the error stack */
1855
11
    if (estack->nused)
1856
10
        if (H5E__clear_entries(estack, estack->nused) < 0)
1857
0
            HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't clear error stack");
1858
1859
11
done:
1860
11
    FUNC_LEAVE_NOAPI(ret_value)
1861
11
} /* end H5E_clear_stack() */
1862
1863
/*-------------------------------------------------------------------------
1864
 * Function:    H5E__destroy_stack
1865
 *
1866
 * Purpose:     Clear all internal state within an error stack, as a precursor to freeing it.
1867
 *
1868
 *              At present, this is nearly identical to H5E_clear_stack(),
1869
 *              but if additional resources are added to the error stack in the future,
1870
 *              they will only be released by this routine and not by H5E_clear_stack().
1871
 *
1872
 * Return:      SUCCEED/FAIL
1873
 *
1874
 *-------------------------------------------------------------------------
1875
 */
1876
herr_t
1877
H5E__destroy_stack(H5E_stack_t *estack)
1878
0
{
1879
0
    herr_t ret_value = SUCCEED; /* Return value */
1880
1881
0
    FUNC_ENTER_PACKAGE
1882
1883
    /* Check for 'default' error stack */
1884
0
    if (estack == NULL)
1885
0
        if (NULL == (estack = H5E__get_my_stack()))
1886
0
            HGOTO_ERROR(H5E_ERROR, H5E_CANTGET, FAIL, "can't get current error stack");
1887
1888
    /* Empty the error stack */
1889
0
    if (estack->nused)
1890
0
        if (H5E__clear_entries(estack, estack->nused) < 0)
1891
0
            HGOTO_ERROR(H5E_ERROR, H5E_CANTSET, FAIL, "can't clear error stack");
1892
1893
0
done:
1894
0
    FUNC_LEAVE_NOAPI(ret_value)
1895
0
} /* end H5E__destroy_stack() */
1896
1897
/*-------------------------------------------------------------------------
1898
 * Function:    H5E__pop
1899
 *
1900
 * Purpose:     Private function to delete some error messages from the top
1901
 *              of error stack.
1902
 *
1903
 * Return:      SUCCEED/FAIL
1904
 *
1905
 *-------------------------------------------------------------------------
1906
 */
1907
herr_t
1908
H5E__pop(H5E_stack_t *estack, size_t count)
1909
0
{
1910
0
    herr_t ret_value = SUCCEED; /* Return value */
1911
1912
0
    FUNC_ENTER_PACKAGE
1913
1914
    /* Sanity check */
1915
0
    assert(estack);
1916
0
    assert(estack->nused >= count);
1917
1918
    /* Remove the entries from the error stack */
1919
0
    if (H5E__clear_entries(estack, count) < 0)
1920
0
        HGOTO_ERROR(H5E_ERROR, H5E_CANTRELEASE, FAIL, "can't remove errors from stack");
1921
1922
0
done:
1923
0
    FUNC_LEAVE_NOAPI(ret_value)
1924
0
} /* end H5E__pop() */
1925
1926
/*-------------------------------------------------------------------------
1927
 * Function:    H5E_dump_api_stack
1928
 *
1929
 * Purpose:     Private function to dump the error stack during an error in
1930
 *              an API function if a callback function is defined for the
1931
 *              current error stack.
1932
 *
1933
 * Return:      SUCCEED/FAIL
1934
 *
1935
 *-------------------------------------------------------------------------
1936
 */
1937
herr_t
1938
H5E_dump_api_stack(void)
1939
10
{
1940
10
    H5E_stack_t *estack    = H5E__get_my_stack();
1941
10
    herr_t       ret_value = SUCCEED; /* Return value */
1942
1943
10
    FUNC_ENTER_NOAPI(FAIL)
1944
1945
10
    assert(estack);
1946
1947
#ifdef H5_NO_DEPRECATED_SYMBOLS
1948
    if (estack->auto_op.func2) {
1949
        /* Prepare & restore library for user callback */
1950
        H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR)
1951
            {
1952
                (void)((estack->auto_op.func2)(H5E_DEFAULT, estack->auto_data));
1953
            }
1954
        H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR)
1955
    }
1956
#else  /* H5_NO_DEPRECATED_SYMBOLS */
1957
10
    if (estack->auto_op.vers == 1) {
1958
0
        if (estack->auto_op.func1) {
1959
            /* Prepare & restore library for user callback */
1960
0
            H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR)
1961
0
                {
1962
0
                    (void)((estack->auto_op.func1)(estack->auto_data));
1963
0
                }
1964
0
            H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR)
1965
0
        }
1966
0
    } /* end if */
1967
10
    else {
1968
10
        if (estack->auto_op.func2) {
1969
            /* Prepare & restore library for user callback */
1970
10
            H5_BEFORE_USER_CB_NOERR(H5_ITER_ERROR)
1971
10
                {
1972
10
                    (void)((estack->auto_op.func2)(H5E_DEFAULT, estack->auto_data));
1973
10
                }
1974
10
            H5_AFTER_USER_CB_NOERR(H5_ITER_ERROR)
1975
10
        }
1976
10
    } /* end else */
1977
10
#endif /* H5_NO_DEPRECATED_SYMBOLS */
1978
1979
10
done:
1980
10
    FUNC_LEAVE_NOAPI(ret_value)
1981
10
} /* end H5E_dump_api_stack() */
1982
1983
/*-------------------------------------------------------------------------
1984
 * Function:    H5E_pause_stack
1985
 *
1986
 * Purpose:     Pause pushing errors on the default error stack.
1987
 *
1988
 *              Generally used via the H5E_PAUSE_ERRORS / H5E_RESUME_ERRORS
1989
 *              macros.
1990
 *
1991
 *              When one needs to temporarily disable recording errors while
1992
 *              trying something that's likely or expected to fail.  The code
1993
 *              to try can be nested between these macros like:
1994
 *
1995
 *              H5E_PAUSE_ERRORS {
1996
 *                  ...stuff here that's likely to fail...
1997
 *              } H5E_RESUME_ERRORS
1998
 *
1999
 *              Warning: don't break, return, or longjmp() from the block of
2000
 *              code or the error reporting won't be properly restored!
2001
 *
2002
 * Return:      none
2003
 *
2004
 *-------------------------------------------------------------------------
2005
 */
2006
void
2007
H5E_pause_stack(void)
2008
0
{
2009
0
    H5E_stack_t *estack = H5E__get_my_stack();
2010
2011
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
2012
2013
0
    assert(estack);
2014
2015
    /* Increment pause counter */
2016
0
    estack->paused++;
2017
2018
0
    FUNC_LEAVE_NOAPI_VOID
2019
0
} /* end H5E_pause_stack() */
2020
2021
/*-------------------------------------------------------------------------
2022
 * Function:    H5E_resume_stack
2023
 *
2024
 * Purpose:     Resume pushing errors on the default error stack.
2025
 *
2026
 *              Generally used via the H5E_PAUSE_ERRORS / H5E_RESUME_ERRORS
2027
 *              macros.
2028
 *
2029
 *              When one needs to temporarily disable recording errors while
2030
 *              trying something that's likely or expected to fail.  The code
2031
 *              to try can be nested between these macros like:
2032
 *
2033
 *              H5E_PAUSE_ERRORS {
2034
 *                  ...stuff here that's likely to fail...
2035
 *              } H5E_RESUME_ERRORS
2036
 *
2037
 *              Warning: don't break, return, or longjmp() from the block of
2038
 *              code or the error reporting won't be properly restored!
2039
 *
2040
 * Return:      none
2041
 *
2042
 *-------------------------------------------------------------------------
2043
 */
2044
void
2045
H5E_resume_stack(void)
2046
0
{
2047
0
    H5E_stack_t *estack = H5E__get_my_stack();
2048
2049
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
2050
2051
0
    assert(estack);
2052
0
    assert(estack->paused);
2053
2054
    /* Decrement pause counter */
2055
0
    estack->paused--;
2056
2057
0
    FUNC_LEAVE_NOAPI_VOID
2058
0
} /* end H5E_resume_stack() */