Skip to content

Commit 33af2db

Browse files
Use an enum instead of storing an error string.
1 parent 21a49b4 commit 33af2db

File tree

3 files changed

+191
-49
lines changed

3 files changed

+191
-49
lines changed

Include/internal/pycore_importdl.h

+21-4
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ extern "C" {
1515
extern const char *_PyImport_DynLoadFiletab[];
1616

1717

18-
typedef PyObject *(*PyModInitFunction)(void);
19-
18+
/* Input for loading an extension module. */
2019
struct _Py_ext_module_loader_info {
2120
PyObject *filename;
2221
#ifndef MS_WINDOWS
@@ -43,6 +42,7 @@ extern int _Py_ext_module_loader_info_init_from_spec(
4342
struct _Py_ext_module_loader_info *info,
4443
PyObject *spec);
4544

45+
/* The result from running an extension module's init function. */
4646
struct _Py_ext_module_loader_result {
4747
PyModuleDef *def;
4848
PyObject *module;
@@ -52,11 +52,28 @@ struct _Py_ext_module_loader_result {
5252
_Py_ext_module_loader_result_MULTIPHASE = 2,
5353
_Py_ext_module_loader_result_INVALID = 3,
5454
} kind;
55-
char err[200];
55+
struct _Py_ext_module_loader_result_error *err;
56+
struct _Py_ext_module_loader_result_error {
57+
enum _Py_ext_module_loader_result_error_kind {
58+
_Py_ext_module_loader_result_EXCEPTION = 0,
59+
_Py_ext_module_loader_result_ERR_MISSING = 1,
60+
_Py_ext_module_loader_result_ERR_UNREPORTED_EXC = 2,
61+
_Py_ext_module_loader_result_ERR_UNINITIALIZED = 3,
62+
_Py_ext_module_loader_result_ERR_NONASCII_NOT_MULTIPHASE = 4,
63+
_Py_ext_module_loader_result_ERR_NOT_MODULE = 5,
64+
_Py_ext_module_loader_result_ERR_MISSING_DEF = 6,
65+
} kind;
66+
PyObject *exc;
67+
} _err;
5668
};
57-
extern void _Py_ext_module_loader_result_apply_error(
69+
extern void _Py_ext_module_loader_result_clear(
5870
struct _Py_ext_module_loader_result *res);
71+
extern void _Py_ext_module_loader_result_apply_error(
72+
struct _Py_ext_module_loader_result *res,
73+
const char *name);
5974

75+
/* The module init function. */
76+
typedef PyObject *(*PyModInitFunction)(void);
6077
extern PyModInitFunction _PyImport_GetModInitFunc(
6178
struct _Py_ext_module_loader_info *info,
6279
FILE *fp);

Python/import.c

+16-6
Original file line numberDiff line numberDiff line change
@@ -1377,14 +1377,21 @@ import_find_extension(PyThreadState *tstate,
13771377
}
13781378
struct _Py_ext_module_loader_result res;
13791379
if (_PyImport_RunModInitFunc(def->m_base.m_init, info, &res) < 0) {
1380-
_Py_ext_module_loader_result_apply_error(&res);
1380+
_Py_ext_module_loader_result_apply_error(&res, name_buf);
1381+
_Py_ext_module_loader_result_clear(&res);
13811382
return NULL;
13821383
}
1383-
assert(!PyErr_Occurred());
1384+
assert(!PyErr_Occurred() && res.err == NULL);
13841385
assert(res.kind == _Py_ext_module_loader_result_SINGLEPHASE);
13851386
mod = res.module;
1387+
/* Tchnically, the init function could return a different module def.
1388+
* Then we would probably need to update the global cache.
1389+
* However, we don't expect anyone to change the def. */
1390+
assert(res.def == def);
1391+
_Py_ext_module_loader_result_clear(&res);
13861392

13871393
// XXX __file__ doesn't get set!
1394+
13881395
if (PyObject_SetItem(modules, info->name, mod) == -1) {
13891396
Py_DECREF(mod);
13901397
return NULL;
@@ -1411,15 +1418,16 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
14111418
{
14121419
PyObject *mod = NULL;
14131420
PyModuleDef *def = NULL;
1421+
const char *name_buf = PyBytes_AS_STRING(info->name_encoded);
14141422

14151423
struct _Py_ext_module_loader_result res;
14161424
if (_PyImport_RunModInitFunc(p0, info, &res) < 0) {
14171425
/* We discard res.def. */
14181426
assert(res.module == NULL);
1419-
_Py_ext_module_loader_result_apply_error(&res);
1427+
_Py_ext_module_loader_result_apply_error(&res, name_buf);
14201428
goto finally;
14211429
}
1422-
assert(!PyErr_Occurred());
1430+
assert(!PyErr_Occurred() && res.err == NULL);
14231431

14241432
mod = res.module;
14251433
res.module = NULL;
@@ -1439,7 +1447,6 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
14391447
assert(is_singlephase(def));
14401448
assert(PyModule_Check(mod));
14411449

1442-
const char *name_buf = PyBytes_AS_STRING(info->name_encoded);
14431450
if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) {
14441451
Py_CLEAR(mod);
14451452
goto finally;
@@ -1448,13 +1455,14 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
14481455
/* Remember pointer to module init function. */
14491456
def->m_base.m_init = p0;
14501457

1458+
/* Remember the filename as the __file__ attribute */
14511459
if (info->filename != NULL) {
1452-
/* Remember the filename as the __file__ attribute */
14531460
if (PyModule_AddObjectRef(mod, "__file__", info->filename) < 0) {
14541461
PyErr_Clear(); /* Not important enough to report */
14551462
}
14561463
}
14571464

1465+
/* Update global import state. */
14581466
struct singlephase_global_update singlephase = {0};
14591467
// gh-88216: Extensions and def->m_base.m_copy can be updated
14601468
// when the extension module doesn't support sub-interpreters.
@@ -1471,6 +1479,7 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
14711479
goto finally;
14721480
}
14731481

1482+
/* Update per-interpreter import state. */
14741483
PyObject *modules = get_modules_dict(tstate, true);
14751484
if (finish_singlephase_extension(
14761485
tstate, mod, def, info->name, modules) < 0)
@@ -1481,6 +1490,7 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
14811490
}
14821491

14831492
finally:
1493+
_Py_ext_module_loader_result_clear(&res);
14841494
return mod;
14851495
}
14861496

0 commit comments

Comments
 (0)