Coverage Report

Created: 2026-10-31 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Python/dynload_shlib.c
Line
Count
Source
1
2
/* Support for dynamic loading of extension modules */
3
4
#include "Python.h"
5
#include "pycore_fileutils.h"     // struct _Py_stat_struct
6
#include "pycore_import.h"        // _PyImport_GetDLOpenFlags()
7
#include "pycore_importdl.h"
8
#include "pycore_interp.h"        // _PyInterpreterState.dlopenflags
9
#include "pycore_pystate.h"       // _PyInterpreterState_GET()
10
11
#include <sys/types.h>
12
#include <sys/stat.h>
13
14
#ifdef HAVE_DLFCN_H
15
#include <dlfcn.h>
16
#endif
17
18
#if (defined(__OpenBSD__) || defined(__NetBSD__)) && !defined(__ELF__)
19
#define LEAD_UNDERSCORE "_"
20
#else
21
402
#define LEAD_UNDERSCORE ""
22
#endif
23
24
/* The .so extension module ABI tag, supplied by the Makefile via
25
   Makefile.pre.in and configure.  This is used to discriminate between
26
   incompatible .so files so that extensions for different Python builds can
27
   live in the same directory.  E.g. foomodule.cpython-32.so
28
*/
29
30
const char *_PyImport_DynLoadFiletab[] = {
31
#ifdef __CYGWIN__
32
    "." SOABI ".dll",
33
    ".dll",
34
#else  /* !__CYGWIN__ */
35
    "." SOABI ".so",
36
#ifdef ALT_SOABI
37
    "." ALT_SOABI ".so",
38
#endif
39
#ifndef Py_GIL_DISABLED
40
#ifdef SOABI_PLATFORM
41
    ".abi" PYTHON_ABI_STRING "-" SOABI_PLATFORM ".so",
42
#endif  /* SOABI_PLATFORM */
43
    ".abi" PYTHON_ABI_STRING ".so",
44
#endif  /* Py_GIL_DISABLED */
45
#ifdef SOABI_PLATFORM
46
    ".abi" PYTHON_ABI_STRING "t-" SOABI_PLATFORM ".so",
47
#endif  /* SOABI_PLATFORM */
48
    ".abi" PYTHON_ABI_STRING "t.so",
49
    ".so",
50
#endif  /* __CYGWIN__ */
51
    NULL,
52
};
53
54
55
dl_funcptr
56
_PyImport_FindSharedFuncptr(const char *prefix,
57
                            const char *shortname,
58
                            const char *pathname, FILE *fp)
59
402
{
60
402
    dl_funcptr p;
61
402
    void *handle;
62
402
    char funcname[258];
63
402
    char pathbuf[260];
64
402
    int dlopenflags=0;
65
66
402
    if (strchr(pathname, '/') == NULL) {
67
        /* Prefix bare filename with "./" */
68
0
        PyOS_snprintf(pathbuf, sizeof(pathbuf), "./%-.255s", pathname);
69
0
        pathname = pathbuf;
70
0
    }
71
72
402
    PyOS_snprintf(funcname, sizeof(funcname),
73
402
                  LEAD_UNDERSCORE "%.20s_%.200s", prefix, shortname);
74
75
402
    if (fp != NULL) {
76
0
        struct _Py_stat_struct status;
77
0
        if (_Py_fstat(fileno(fp), &status) == -1)
78
0
            return NULL;
79
0
    }
80
81
402
    dlopenflags = _PyImport_GetDLOpenFlags(_PyInterpreterState_GET());
82
83
402
    handle = dlopen(pathname, dlopenflags);
84
85
402
    if (handle == NULL) {
86
0
        PyObject *mod_name;
87
0
        PyObject *path;
88
0
        PyObject *error_ob;
89
0
        const char *error = dlerror();
90
0
        if (error == NULL)
91
0
            error = "unknown dlopen() error";
92
0
        error_ob = PyUnicode_DecodeLocale(error, "surrogateescape");
93
0
        if (error_ob == NULL)
94
0
            return NULL;
95
0
        mod_name = PyUnicode_FromString(shortname);
96
0
        if (mod_name == NULL) {
97
0
            Py_DECREF(error_ob);
98
0
            return NULL;
99
0
        }
100
0
        path = PyUnicode_DecodeFSDefault(pathname);
101
0
        if (path == NULL) {
102
0
            Py_DECREF(error_ob);
103
0
            Py_DECREF(mod_name);
104
0
            return NULL;
105
0
        }
106
0
        PyErr_SetImportError(error_ob, mod_name, path);
107
0
        Py_DECREF(error_ob);
108
0
        Py_DECREF(mod_name);
109
0
        Py_DECREF(path);
110
0
        return NULL;
111
0
    }
112
402
    p = (dl_funcptr) dlsym(handle, funcname);
113
402
    return p;
114
402
}