ยปCore Development>Code coverage>Python/dynload_win.c

Python code coverage for Python/dynload_win.c

#countcontent
1n/a
2n/a/* Support for dynamic loading of extension modules */
3n/a
4n/a#include "Python.h"
5n/a
6n/a#ifdef HAVE_DIRECT_H
7n/a#include <direct.h>
8n/a#endif
9n/a#include <ctype.h>
10n/a
11n/a#include "importdl.h"
12n/a#include "patchlevel.h"
13n/a#include <windows.h>
14n/a
15n/a// "activation context" magic - see dl_nt.c...
16n/a#if HAVE_SXS
17n/aextern ULONG_PTR _Py_ActivateActCtx();
18n/avoid _Py_DeactivateActCtx(ULONG_PTR cookie);
19n/a#endif
20n/a
21n/a#ifdef _DEBUG
22n/a#define PYD_DEBUG_SUFFIX "_d"
23n/a#else
24n/a#define PYD_DEBUG_SUFFIX ""
25n/a#endif
26n/a
27n/a#ifdef PYD_PLATFORM_TAG
28n/a#define PYD_TAGGED_SUFFIX PYD_DEBUG_SUFFIX ".cp" Py_STRINGIFY(PY_MAJOR_VERSION) Py_STRINGIFY(PY_MINOR_VERSION) "-" PYD_PLATFORM_TAG ".pyd"
29n/a#else
30n/a#define PYD_TAGGED_SUFFIX PYD_DEBUG_SUFFIX ".cp" Py_STRINGIFY(PY_MAJOR_VERSION) Py_STRINGIFY(PY_MINOR_VERSION) ".pyd"
31n/a#endif
32n/a
33n/a#define PYD_UNTAGGED_SUFFIX PYD_DEBUG_SUFFIX ".pyd"
34n/a
35n/aconst char *_PyImport_DynLoadFiletab[] = {
36n/a PYD_TAGGED_SUFFIX,
37n/a PYD_UNTAGGED_SUFFIX,
38n/a NULL
39n/a};
40n/a
41n/a/* Case insensitive string compare, to avoid any dependencies on particular
42n/a C RTL implementations */
43n/a
44n/astatic int strcasecmp (const char *string1, const char *string2)
45n/a{
46n/a int first, second;
47n/a
48n/a do {
49n/a first = tolower(*string1);
50n/a second = tolower(*string2);
51n/a string1++;
52n/a string2++;
53n/a } while (first && first == second);
54n/a
55n/a return (first - second);
56n/a}
57n/a
58n/a
59n/a/* Function to return the name of the "python" DLL that the supplied module
60n/a directly imports. Looks through the list of imported modules and
61n/a returns the first entry that starts with "python" (case sensitive) and
62n/a is followed by nothing but numbers until the separator (period).
63n/a
64n/a Returns a pointer to the import name, or NULL if no matching name was
65n/a located.
66n/a
67n/a This function parses through the PE header for the module as loaded in
68n/a memory by the system loader. The PE header is accessed as documented by
69n/a Microsoft in the MSDN PE and COFF specification (2/99), and handles
70n/a both PE32 and PE32+. It only worries about the direct import table and
71n/a not the delay load import table since it's unlikely an extension is
72n/a going to be delay loading Python (after all, it's already loaded).
73n/a
74n/a If any magic values are not found (e.g., the PE header or optional
75n/a header magic), then this function simply returns NULL. */
76n/a
77n/a#define DWORD_AT(mem) (*(DWORD *)(mem))
78n/a#define WORD_AT(mem) (*(WORD *)(mem))
79n/a
80n/astatic char *GetPythonImport (HINSTANCE hModule)
81n/a{
82n/a unsigned char *dllbase, *import_data, *import_name;
83n/a DWORD pe_offset, opt_offset;
84n/a WORD opt_magic;
85n/a int num_dict_off, import_off;
86n/a
87n/a /* Safety check input */
88n/a if (hModule == NULL) {
89n/a return NULL;
90n/a }
91n/a
92n/a /* Module instance is also the base load address. First portion of
93n/a memory is the MS-DOS loader, which holds the offset to the PE
94n/a header (from the load base) at 0x3C */
95n/a dllbase = (unsigned char *)hModule;
96n/a pe_offset = DWORD_AT(dllbase + 0x3C);
97n/a
98n/a /* The PE signature must be "PE\0\0" */
99n/a if (memcmp(dllbase+pe_offset,"PE\0\0",4)) {
100n/a return NULL;
101n/a }
102n/a
103n/a /* Following the PE signature is the standard COFF header (20
104n/a bytes) and then the optional header. The optional header starts
105n/a with a magic value of 0x10B for PE32 or 0x20B for PE32+ (PE32+
106n/a uses 64-bits for some fields). It might also be 0x107 for a ROM
107n/a image, but we don't process that here.
108n/a
109n/a The optional header ends with a data dictionary that directly
110n/a points to certain types of data, among them the import entries
111n/a (in the second table entry). Based on the header type, we
112n/a determine offsets for the data dictionary count and the entry
113n/a within the dictionary pointing to the imports. */
114n/a
115n/a opt_offset = pe_offset + 4 + 20;
116n/a opt_magic = WORD_AT(dllbase+opt_offset);
117n/a if (opt_magic == 0x10B) {
118n/a /* PE32 */
119n/a num_dict_off = 92;
120n/a import_off = 104;
121n/a } else if (opt_magic == 0x20B) {
122n/a /* PE32+ */
123n/a num_dict_off = 108;
124n/a import_off = 120;
125n/a } else {
126n/a /* Unsupported */
127n/a return NULL;
128n/a }
129n/a
130n/a /* Now if an import table exists, offset to it and walk the list of
131n/a imports. The import table is an array (ending when an entry has
132n/a empty values) of structures (20 bytes each), which contains (at
133n/a offset 12) a relative address (to the module base) at which a
134n/a string constant holding the import name is located. */
135n/a
136n/a if (DWORD_AT(dllbase + opt_offset + num_dict_off) >= 2) {
137n/a /* We have at least 2 tables - the import table is the second
138n/a one. But still it may be that the table size is zero */
139n/a if (0 == DWORD_AT(dllbase + opt_offset + import_off + sizeof(DWORD)))
140n/a return NULL;
141n/a import_data = dllbase + DWORD_AT(dllbase +
142n/a opt_offset +
143n/a import_off);
144n/a while (DWORD_AT(import_data)) {
145n/a import_name = dllbase + DWORD_AT(import_data+12);
146n/a if (strlen(import_name) >= 6 &&
147n/a !strncmp(import_name,"python",6)) {
148n/a char *pch;
149n/a
150n/a#ifndef _DEBUG
151n/a /* In a release version, don't claim that python3.dll is
152n/a a Python DLL. */
153n/a if (strcmp(import_name, "python3.dll") == 0) {
154n/a import_data += 20;
155n/a continue;
156n/a }
157n/a#endif
158n/a
159n/a /* Ensure python prefix is followed only
160n/a by numbers to the end of the basename */
161n/a pch = import_name + 6;
162n/a#ifdef _DEBUG
163n/a while (*pch && pch[0] != '_' && pch[1] != 'd' && pch[2] != '.') {
164n/a#else
165n/a while (*pch && *pch != '.') {
166n/a#endif
167n/a if (*pch >= '0' && *pch <= '9') {
168n/a pch++;
169n/a } else {
170n/a pch = NULL;
171n/a break;
172n/a }
173n/a }
174n/a
175n/a if (pch) {
176n/a /* Found it - return the name */
177n/a return import_name;
178n/a }
179n/a }
180n/a import_data += 20;
181n/a }
182n/a }
183n/a
184n/a return NULL;
185n/a}
186n/a
187n/adl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix,
188n/a const char *shortname,
189n/a PyObject *pathname, FILE *fp)
190n/a{
191n/a dl_funcptr p;
192n/a char funcname[258], *import_python;
193n/a wchar_t *wpathname;
194n/a
195n/a#ifndef _DEBUG
196n/a _Py_CheckPython3();
197n/a#endif
198n/a
199n/a wpathname = PyUnicode_AsUnicode(pathname);
200n/a if (wpathname == NULL)
201n/a return NULL;
202n/a
203n/a PyOS_snprintf(funcname, sizeof(funcname), "%.20s_%.200s", prefix, shortname);
204n/a
205n/a {
206n/a HINSTANCE hDLL = NULL;
207n/a unsigned int old_mode;
208n/a#if HAVE_SXS
209n/a ULONG_PTR cookie = 0;
210n/a#endif
211n/a
212n/a /* Don't display a message box when Python can't load a DLL */
213n/a old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
214n/a
215n/a#if HAVE_SXS
216n/a cookie = _Py_ActivateActCtx();
217n/a#endif
218n/a /* We use LoadLibraryEx so Windows looks for dependent DLLs
219n/a in directory of pathname first. */
220n/a /* XXX This call doesn't exist in Windows CE */
221n/a hDLL = LoadLibraryExW(wpathname, NULL,
222n/a LOAD_WITH_ALTERED_SEARCH_PATH);
223n/a#if HAVE_SXS
224n/a _Py_DeactivateActCtx(cookie);
225n/a#endif
226n/a
227n/a /* restore old error mode settings */
228n/a SetErrorMode(old_mode);
229n/a
230n/a if (hDLL==NULL){
231n/a PyObject *message;
232n/a unsigned int errorCode;
233n/a
234n/a /* Get an error string from Win32 error code */
235n/a wchar_t theInfo[256]; /* Pointer to error text
236n/a from system */
237n/a int theLength; /* Length of error text */
238n/a
239n/a errorCode = GetLastError();
240n/a
241n/a theLength = FormatMessageW(
242n/a FORMAT_MESSAGE_FROM_SYSTEM |
243n/a FORMAT_MESSAGE_IGNORE_INSERTS, /* flags */
244n/a NULL, /* message source */
245n/a errorCode, /* the message (error) ID */
246n/a MAKELANGID(LANG_NEUTRAL,
247n/a SUBLANG_DEFAULT),
248n/a /* Default language */
249n/a theInfo, /* the buffer */
250n/a sizeof(theInfo) / sizeof(wchar_t), /* size in wchars */
251n/a NULL); /* no additional format args. */
252n/a
253n/a /* Problem: could not get the error message.
254n/a This should not happen if called correctly. */
255n/a if (theLength == 0) {
256n/a message = PyUnicode_FromFormat(
257n/a "DLL load failed with error code %d",
258n/a errorCode);
259n/a } else {
260n/a /* For some reason a \r\n
261n/a is appended to the text */
262n/a if (theLength >= 2 &&
263n/a theInfo[theLength-2] == '\r' &&
264n/a theInfo[theLength-1] == '\n') {
265n/a theLength -= 2;
266n/a theInfo[theLength] = '\0';
267n/a }
268n/a message = PyUnicode_FromString(
269n/a "DLL load failed: ");
270n/a
271n/a PyUnicode_AppendAndDel(&message,
272n/a PyUnicode_FromWideChar(
273n/a theInfo,
274n/a theLength));
275n/a }
276n/a if (message != NULL) {
277n/a PyObject *shortname_obj = PyUnicode_FromString(shortname);
278n/a PyErr_SetImportError(message, shortname_obj, pathname);
279n/a Py_XDECREF(shortname_obj);
280n/a Py_DECREF(message);
281n/a }
282n/a return NULL;
283n/a } else {
284n/a char buffer[256];
285n/a
286n/a PyOS_snprintf(buffer, sizeof(buffer),
287n/a#ifdef _DEBUG
288n/a "python%d%d_d.dll",
289n/a#else
290n/a "python%d%d.dll",
291n/a#endif
292n/a PY_MAJOR_VERSION,PY_MINOR_VERSION);
293n/a import_python = GetPythonImport(hDLL);
294n/a
295n/a if (import_python &&
296n/a strcasecmp(buffer,import_python)) {
297n/a PyErr_Format(PyExc_ImportError,
298n/a "Module use of %.150s conflicts "
299n/a "with this version of Python.",
300n/a import_python);
301n/a FreeLibrary(hDLL);
302n/a return NULL;
303n/a }
304n/a }
305n/a p = GetProcAddress(hDLL, funcname);
306n/a }
307n/a
308n/a return p;
309n/a}