Coverage Report

Created: 2026-03-04 00:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5PLint.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
 * Purpose: Internal routines for managing plugins.
15
 *
16
 */
17
18
/****************/
19
/* Module Setup */
20
/****************/
21
22
#include "H5PLmodule.h" /* This source code file is part of the H5PL module */
23
24
/***********/
25
/* Headers */
26
/***********/
27
#include "H5private.h"  /* Generic Functions            */
28
#include "H5Eprivate.h" /* Error handling               */
29
#include "H5PLpkg.h"    /* Plugin                       */
30
#include "H5Zprivate.h" /* Filter pipeline              */
31
32
/****************/
33
/* Local Macros */
34
/****************/
35
36
/******************/
37
/* Local Typedefs */
38
/******************/
39
40
/********************/
41
/* Local Prototypes */
42
/********************/
43
44
/*********************/
45
/* Package Variables */
46
/*********************/
47
48
/* Package initialization variable */
49
bool H5_PKG_INIT_VAR = false;
50
51
/*****************************/
52
/* Library Private Variables */
53
/*****************************/
54
55
/*******************/
56
/* Local Variables */
57
/*******************/
58
59
/* Bitmask that controls whether classes of plugins
60
 * (e.g.: filters, VOL drivers) can be loaded.
61
 */
62
static unsigned int H5PL_plugin_control_mask_g = H5PL_ALL_PLUGIN;
63
64
/* This flag will be set to false if the HDF5_PLUGIN_PRELOAD
65
 * environment variable was set to H5PL_NO_PLUGIN at
66
 * package initialization.
67
 */
68
static bool H5PL_allow_plugins_g = true;
69
70
/*-------------------------------------------------------------------------
71
 * Function:    H5PL__get_plugin_control_mask
72
 *
73
 * Purpose:     Gets the internal plugin control mask value.
74
 *
75
 * Return:      SUCCEED/FAIL
76
 *
77
 *-------------------------------------------------------------------------
78
 */
79
herr_t
80
H5PL__get_plugin_control_mask(unsigned int *mask /*out*/)
81
0
{
82
0
    herr_t ret_value = SUCCEED; /* Return value */
83
84
0
    FUNC_ENTER_PACKAGE_NOERR
85
86
    /* Check args - Just assert on package functions */
87
0
    assert(mask);
88
89
    /* Return the mask */
90
0
    *mask = H5PL_plugin_control_mask_g;
91
92
0
    FUNC_LEAVE_NOAPI(ret_value)
93
94
0
} /* end H5PL__get_plugin_control_mask() */
95
96
/*-------------------------------------------------------------------------
97
 * Function:    H5PL__set_plugin_control_mask
98
 *
99
 * Purpose:     Sets the internal plugin control mask value.
100
 *
101
 * Return:      SUCCEED/FAIL
102
 *
103
 *-------------------------------------------------------------------------
104
 */
105
herr_t
106
H5PL__set_plugin_control_mask(unsigned int mask)
107
0
{
108
0
    herr_t ret_value = SUCCEED; /* Return value */
109
110
0
    FUNC_ENTER_PACKAGE_NOERR
111
112
    /* Only allow setting this if plugins have not been disabled.
113
     * XXX: Note that we don't consider this an error, but instead
114
     *      silently ignore it. We may want to consider this behavior
115
     *      more carefully.
116
     */
117
0
    if (H5PL_allow_plugins_g)
118
0
        H5PL_plugin_control_mask_g = mask;
119
120
0
    FUNC_LEAVE_NOAPI(ret_value)
121
122
0
} /* end H5PL__set_plugin_control_mask() */
123
124
/*-------------------------------------------------------------------------
125
 * Function:    H5PL__init_package
126
 *
127
 * Purpose:     Initialize any package-specific data and call any init
128
 *              routines for the package.
129
 *
130
 * Return:      Success:        non-negative
131
 *              Failure:        negative
132
 *-------------------------------------------------------------------------
133
 */
134
herr_t
135
H5PL__init_package(void)
136
1
{
137
1
    char  *env_var   = NULL;
138
1
    herr_t ret_value = SUCCEED;
139
140
1
    FUNC_ENTER_PACKAGE
141
142
    /* Check the environment variable to determine if the user wants
143
     * to ignore plugins. The special symbol H5PL_NO_PLUGIN (defined in
144
     * H5PLpublic.h) means we don't want to load plugins.
145
     */
146
1
    if (NULL != (env_var = getenv(HDF5_PLUGIN_PRELOAD)))
147
0
        if (!strcmp(env_var, H5PL_NO_PLUGIN)) {
148
0
            H5PL_plugin_control_mask_g = 0;
149
0
            H5PL_allow_plugins_g       = false;
150
0
        }
151
152
    /* Create the table of previously-loaded plugins */
153
1
    if (H5PL__create_plugin_cache() < 0)
154
0
        HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINIT, FAIL, "can't create plugin cache");
155
156
    /* Create the table of search paths for dynamic libraries */
157
1
    if (H5PL__create_path_table() < 0)
158
0
        HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINIT, FAIL, "can't create plugin search path table");
159
160
1
done:
161
1
    FUNC_LEAVE_NOAPI(ret_value)
162
1
} /* end H5PL__init_package() */
163
164
/*-------------------------------------------------------------------------
165
 * Function:    H5PL_term_package
166
 *
167
 * Purpose:     Terminate the H5PL interface: release all memory, reset all
168
 *              global variables to initial values. This only happens if all
169
 *              types have been destroyed from other interfaces.
170
 *
171
 * Return:      Success:    Positive if any action was taken that might
172
 *                          affect some other interface; zero otherwise
173
 *              Failure:    Negative
174
 *
175
 *-------------------------------------------------------------------------
176
 */
177
int
178
H5PL_term_package(void)
179
4
{
180
4
    bool already_closed = false;
181
4
    int  ret_value      = 0;
182
183
4
    FUNC_ENTER_NOAPI_NOINIT
184
185
2
    if (H5_PKG_INIT_VAR) {
186
        /* Close the plugin cache.
187
         * We need to bump the return value if we did any real work here.
188
         */
189
2
        if (H5PL__close_plugin_cache(&already_closed) < 0)
190
0
            HGOTO_ERROR(H5E_PLUGIN, H5E_CANTFREE, (-1), "problem closing plugin cache");
191
2
        if (!already_closed)
192
1
            ret_value++;
193
194
        /* Close the search path table and free the paths */
195
2
        if (H5PL__close_path_table() < 0)
196
0
            HGOTO_ERROR(H5E_PLUGIN, H5E_CANTFREE, (-1), "problem closing search path table");
197
198
        /* Mark the interface as uninitialized */
199
2
        if (0 == ret_value)
200
1
            H5_PKG_INIT_VAR = false;
201
2
    } /* end if */
202
203
2
done:
204
4
    FUNC_LEAVE_NOAPI(ret_value)
205
4
} /* end H5PL_term_package() */
206
207
/*-------------------------------------------------------------------------
208
 * Function:    H5PL_load
209
 *
210
 * Purpose:     Given the plugin type and identifier, this function searches
211
 *              for and, if found, loads a dynamic plugin library.
212
 *
213
 *              The function searches first in the cached plugins and then
214
 *              in the paths listed in the path table.
215
 *
216
 * Return:      Success:    A pointer to the plugin info
217
 *              Failure:    NULL
218
 *
219
 *-------------------------------------------------------------------------
220
 */
221
const void *
222
H5PL_load(H5PL_type_t type, const H5PL_key_t *key)
223
0
{
224
0
    H5PL_search_params_t search_params;       /* Plugin search parameters     */
225
0
    bool                 found       = false; /* Whether the plugin was found */
226
0
    const void          *plugin_info = NULL;  /* Information from the plugin  */
227
0
    const void          *ret_value   = NULL;
228
229
0
    FUNC_ENTER_NOAPI(NULL)
230
231
    /* Check if plugins can be loaded for this plugin type */
232
0
    switch (type) {
233
0
        case H5PL_TYPE_FILTER:
234
0
            if ((H5PL_plugin_control_mask_g & H5PL_FILTER_PLUGIN) == 0)
235
0
                HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, NULL, "filter plugins disabled");
236
0
            break;
237
238
0
        case H5PL_TYPE_VOL:
239
0
            if ((H5PL_plugin_control_mask_g & H5PL_VOL_PLUGIN) == 0)
240
0
                HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, NULL,
241
0
                            "Virtual Object Layer (VOL) driver plugins disabled");
242
0
            break;
243
244
0
        case H5PL_TYPE_VFD:
245
0
            if ((H5PL_plugin_control_mask_g & H5PL_VFD_PLUGIN) == 0)
246
0
                HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, NULL, "Virtual File Driver (VFD) plugins disabled");
247
0
            break;
248
249
0
        case H5PL_TYPE_ERROR:
250
0
        case H5PL_TYPE_NONE:
251
0
        default:
252
0
            HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, NULL, "Invalid plugin type specified");
253
0
    }
254
255
    /* Set up the search parameters */
256
0
    search_params.type = type;
257
0
    search_params.key  = key;
258
259
    /* Search in the table of already loaded plugin libraries */
260
0
    if (H5PL__find_plugin_in_cache(&search_params, &found, &plugin_info) < 0)
261
0
        HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, NULL, "search in plugin cache failed");
262
263
    /* If not found, try iterating through the path table to find an appropriate plugin */
264
0
    if (!found)
265
0
        if (H5PL__find_plugin_in_path_table(&search_params, &found, &plugin_info) < 0)
266
0
            HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, NULL,
267
0
                        "can't find plugin in the paths either set by HDF5_PLUGIN_PATH, or default location, "
268
0
                        "or set by H5PLxxx functions");
269
270
    /* Set the return value we found the plugin */
271
0
    if (found)
272
0
        ret_value = plugin_info;
273
0
    else
274
0
        HGOTO_ERROR(H5E_PLUGIN, H5E_NOTFOUND, NULL,
275
0
                    "can't find plugin. Check either HDF5_VOL_CONNECTOR, HDF5_PLUGIN_PATH, default location, "
276
0
                    "or path set by H5PLxxx functions");
277
278
0
done:
279
0
    FUNC_LEAVE_NOAPI(ret_value)
280
0
} /* end H5PL_load() */
281
282
/*-------------------------------------------------------------------------
283
 * Function:    H5PL__open
284
 *
285
 * Purpose:     Opens a plugin.
286
 *
287
 *              `path` specifies the path to the plugin library file.
288
 *
289
 *              `type` specifies the type of plugin being searched for and
290
 *              will be used to verify that a loaded plugin matches the
291
 *              type requested. H5PL_TYPE_NONE may be passed, in which case
292
 *              no plugin type verification is performed. This is most
293
 *              useful when iterating over available plugins without regard
294
 *              to their types.
295
 *
296
 *              `key` specifies the information that will be used to find a
297
 *              specific plugin. For filter plugins, this is typically an
298
 *              integer identifier. For VOL connector and VFD plugins, this
299
 *              is typically either an integer identifier or a name string.
300
 *              After a plugin has been opened, this information will be
301
 *              compared against the relevant information provided by the
302
 *              plugin to ensure that the plugin is a match. If
303
 *              H5PL_TYPE_NONE is provided for `type`, then `key` should be
304
 *              NULL.
305
 *
306
 *              On successful open of a plugin, the `success` parameter
307
 *              will be set to true and the `plugin_type` and `plugin_info`
308
 *              parameters will be filled appropriately. On failure, the
309
 *              `success` parameter will be set to false, the `plugin_type`
310
 *              parameter will be set to H5PL_TYPE_ERROR and the
311
 *              `plugin_info` parameter will be set to NULL.
312
 *
313
 * Return:      SUCCEED/FAIL
314
 *
315
 *-------------------------------------------------------------------------
316
 */
317
herr_t
318
H5PL__open(const char *path, H5PL_type_t type, const H5PL_key_t *key, bool *success, H5PL_type_t *plugin_type,
319
           const void **plugin_info)
320
0
{
321
0
    H5PL_HANDLE            handle          = NULL;
322
0
    H5PL_get_plugin_info_t get_plugin_info = NULL;
323
0
    H5PL_get_plugin_type_t get_plugin_type = NULL;
324
0
    H5PL_type_t            loaded_plugin_type;
325
0
    H5PL_key_t             tmp_key;
326
0
    herr_t                 ret_value = SUCCEED;
327
328
0
    FUNC_ENTER_PACKAGE
329
330
    /* Check args - Just assert on package functions */
331
0
    assert(path);
332
0
    if (type == H5PL_TYPE_NONE)
333
0
        assert(!key);
334
0
    assert(success);
335
0
    assert(plugin_info);
336
337
    /* Initialize out parameters */
338
0
    *success     = false;
339
0
    *plugin_info = NULL;
340
0
    if (plugin_type)
341
0
        *plugin_type = H5PL_TYPE_ERROR;
342
343
    /* There are different reasons why a library can't be open, e.g. wrong architecture.
344
     * If we can't open the library, just return.
345
     */
346
0
    if (NULL == (handle = H5PL_OPEN_DLIB(path))) {
347
0
        H5PL_CLR_ERROR; /* clear error */
348
0
        HGOTO_DONE(SUCCEED);
349
0
    }
350
351
    /* NOTE: We turn off -Wpedantic to quiet a warning about converting object
352
     *       pointers to function pointers, which is undefined in ANSI C. This
353
     *       is basically unavoidable due to the nature of dlsym() and *is*
354
     *       defined in POSIX, so it's fine.
355
     */
356
357
    /* Return a handle for the function H5PLget_plugin_type in the dynamic library.
358
     * The plugin library is supposed to define this function.
359
     */
360
0
    H5_WARN_OBJ_FXN_POINTER_CONVERSION_OFF
361
0
    if (NULL == (get_plugin_type = (H5PL_get_plugin_type_t)H5PL_GET_LIB_FUNC(handle, "H5PLget_plugin_type")))
362
0
        HGOTO_DONE(SUCCEED);
363
0
    H5_WARN_OBJ_FXN_POINTER_CONVERSION_ON
364
365
    /* Return a handle for the function H5PLget_plugin_info in the dynamic library.
366
     * The plugin library is supposed to define this function.
367
     */
368
0
    H5_WARN_OBJ_FXN_POINTER_CONVERSION_OFF
369
0
    if (NULL == (get_plugin_info = (H5PL_get_plugin_info_t)H5PL_GET_LIB_FUNC(handle, "H5PLget_plugin_info")))
370
0
        HGOTO_DONE(SUCCEED);
371
0
    H5_WARN_OBJ_FXN_POINTER_CONVERSION_ON
372
373
    /* Check the plugin type and return if it doesn't match the one passed in */
374
0
    loaded_plugin_type = (H5PL_type_t)(*get_plugin_type)();
375
0
    if ((type != H5PL_TYPE_NONE) && (type != loaded_plugin_type))
376
0
        HGOTO_DONE(SUCCEED);
377
378
    /* Get the plugin information */
379
0
    switch (loaded_plugin_type) {
380
0
        case H5PL_TYPE_FILTER: {
381
0
            const H5Z_class2_t *filter_info;
382
383
            /* Get the plugin info */
384
0
            if (NULL == (filter_info = (const H5Z_class2_t *)(*get_plugin_info)()))
385
0
                HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "can't get filter info from plugin");
386
387
            /* Setup temporary plugin key if one wasn't supplied */
388
0
            if (!key) {
389
0
                tmp_key.id = filter_info->id;
390
0
                key        = &tmp_key;
391
0
            }
392
393
            /* If the filter IDs match, we're done. Set the output parameters. */
394
0
            if (filter_info->id == key->id) {
395
0
                if (plugin_type)
396
0
                    *plugin_type = H5PL_TYPE_FILTER;
397
0
                *plugin_info = (const void *)filter_info;
398
0
                *success     = true;
399
0
            }
400
401
0
            break;
402
0
        }
403
404
0
        case H5PL_TYPE_VOL: {
405
0
            const void *cls;
406
407
            /* Get the plugin info */
408
0
            if (NULL == (cls = (const void *)(*get_plugin_info)()))
409
0
                HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "can't get VOL connector info from plugin");
410
411
            /* Setup temporary plugin key if one wasn't supplied */
412
0
            if (!key) {
413
0
                tmp_key.vol.kind   = H5VL_GET_CONNECTOR_BY_NAME;
414
0
                tmp_key.vol.u.name = ((const H5VL_class_t *)cls)->name;
415
0
                key                = &tmp_key;
416
0
            }
417
418
            /* Ask VOL interface if this class is the one we are looking for and is compatible, etc */
419
0
            if (H5VL_check_plugin_load(cls, key, success) < 0)
420
0
                HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, FAIL, "VOL connector compatibility check failed");
421
422
            /* Check for finding the correct plugin */
423
0
            if (*success) {
424
0
                if (plugin_type)
425
0
                    *plugin_type = H5PL_TYPE_VOL;
426
0
                *plugin_info = cls;
427
0
            }
428
429
0
            break;
430
0
        }
431
432
0
        case H5PL_TYPE_VFD: {
433
0
            const void *cls;
434
435
            /* Get the plugin info */
436
0
            if (NULL == (cls = (const void *)(*get_plugin_info)()))
437
0
                HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "can't get VFD info from plugin");
438
439
            /* Setup temporary plugin key if one wasn't supplied */
440
0
            if (!key) {
441
0
                tmp_key.vfd.kind   = H5FD_GET_DRIVER_BY_NAME;
442
0
                tmp_key.vfd.u.name = ((const H5FD_class_t *)cls)->name;
443
0
                key                = &tmp_key;
444
0
            }
445
446
            /* Ask VFD interface if this class is the one we are looking for and is compatible, etc */
447
0
            if (H5FD_check_plugin_load(cls, key, success) < 0)
448
0
                HGOTO_ERROR(H5E_PLUGIN, H5E_CANTLOAD, FAIL, "VFD compatibility check failed");
449
450
            /* Check for finding the correct plugin */
451
0
            if (*success) {
452
0
                if (plugin_type)
453
0
                    *plugin_type = H5PL_TYPE_VFD;
454
0
                *plugin_info = cls;
455
0
            }
456
457
0
            break;
458
0
        }
459
460
0
        case H5PL_TYPE_ERROR:
461
0
        case H5PL_TYPE_NONE:
462
0
        default:
463
0
            HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "Invalid plugin type specified");
464
0
    } /* end switch */
465
466
    /* If we found the correct plugin, store it in the cache */
467
0
    if (*success)
468
0
        if (H5PL__add_plugin(loaded_plugin_type, key, handle))
469
0
            HGOTO_ERROR(H5E_PLUGIN, H5E_CANTINSERT, FAIL, "unable to add new plugin to plugin cache");
470
471
0
done:
472
0
    if (!(*success) && handle)
473
0
        if (H5PL__close(handle) < 0)
474
0
            HDONE_ERROR(H5E_PLUGIN, H5E_CLOSEERROR, FAIL, "can't close dynamic library");
475
476
0
    FUNC_LEAVE_NOAPI(ret_value)
477
0
} /* end H5PL__open() */
478
479
/*-------------------------------------------------------------------------
480
 * Function:    H5PL__close
481
 *
482
 * Purpose:     Closes the handle for dynamic library
483
 *
484
 * Return:      SUCCEED/FAIL
485
 *
486
 *-------------------------------------------------------------------------
487
 */
488
herr_t
489
H5PL__close(H5PL_HANDLE handle)
490
0
{
491
0
    FUNC_ENTER_PACKAGE_NOERR
492
493
0
    H5PL_CLOSE_LIB(handle);
494
495
0
    FUNC_LEAVE_NOAPI(SUCCEED)
496
0
} /* end H5PL__close() */
497
498
/*-------------------------------------------------------------------------
499
 * Function:    H5PL_iterate
500
 *
501
 * Purpose:     Iterates over all the available plugins and calls the
502
 *              specified callback function on each plugin.
503
 *
504
 * Return:      H5_ITER_CONT if all plugins are processed successfully
505
 *              H5_ITER_STOP if short-circuit success occurs while
506
 *                  processing plugins
507
 *              H5_ITER_ERROR if an error occurs while processing plugins
508
 *
509
 *-------------------------------------------------------------------------
510
 */
511
herr_t
512
H5PL_iterate(H5PL_iterate_type_t iter_type, H5PL_iterate_t iter_op, void *op_data)
513
4
{
514
4
    herr_t ret_value = H5_ITER_CONT;
515
516
4
    FUNC_ENTER_NOAPI(H5_ITER_ERROR)
517
518
4
    ret_value = H5PL__path_table_iterate(iter_type, iter_op, op_data);
519
520
4
done:
521
4
    FUNC_LEAVE_NOAPI(ret_value)
522
4
} /* end H5PL_iterate() */