Skip to content

Commit 64e1dc8

Browse files
Raise ImportError in subinterpreters for incompatible single-phase init extensions.
1 parent ed505a6 commit 64e1dc8

File tree

3 files changed

+59
-11
lines changed

3 files changed

+59
-11
lines changed

Lib/test/test_import/__init__.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,6 +1456,22 @@ def check_compatible_shared(self, name, *, strict=False):
14561456
out = os.read(r, 100)
14571457
self.assertEqual(out, b'okay')
14581458

1459+
def check_incompatible_shared(self, name):
1460+
# Differences from check_compatible_shared():
1461+
# * verify that import fails
1462+
# * "strict" is always True
1463+
__import__(name)
1464+
1465+
r, w = self.pipe()
1466+
ret = run_in_subinterp_with_config(
1467+
self.import_script(name, w),
1468+
**self.RUN_KWARGS,
1469+
check_multi_interp_extensions=True,
1470+
)
1471+
self.assertEqual(ret, 0)
1472+
out = os.read(r, 100).decode('utf-8')
1473+
self.assertEqual(out, f'ImportError: module {name} does not support loading in subinterpreters')
1474+
14591475
def check_compatible_isolated(self, name, *, strict=False):
14601476
# Differences from check_compatible_shared():
14611477
# * subinterpreter in a new process
@@ -1477,6 +1493,26 @@ def check_compatible_isolated(self, name, *, strict=False):
14771493
self.assertEqual(err, b'')
14781494
self.assertEqual(out, b'okay')
14791495

1496+
def check_incompatible_isolated(self, name):
1497+
# Differences from check_compatible_isolated():
1498+
# * verify that import fails
1499+
# * "strict" is always True
1500+
_, out, err = script_helper.assert_python_ok('-c', textwrap.dedent(f'''
1501+
import _testcapi, sys
1502+
assert {name!r} not in sys.modules, {name!r}
1503+
ret = _testcapi.run_in_subinterp_with_config(
1504+
{self.import_script(name, "sys.stdout.fileno()")!r},
1505+
**{self.RUN_KWARGS},
1506+
check_multi_interp_extensions=True,
1507+
)
1508+
assert ret == 0, ret
1509+
'''))
1510+
self.assertEqual(err, b'')
1511+
self.assertEqual(
1512+
out.decode('utf-8'),
1513+
f'ImportError: module {name} does not support loading in subinterpreters',
1514+
)
1515+
14801516
def test_builtin_compat(self):
14811517
module = 'sys'
14821518
with self.subTest(f'{module}: not strict'):
@@ -1500,9 +1536,9 @@ def test_single_init_extension_compat(self):
15001536
with self.subTest(f'{module}: not strict'):
15011537
self.check_compatible_shared(module, strict=False)
15021538
with self.subTest(f'{module}: strict, shared'):
1503-
self.check_compatible_shared(module)
1539+
self.check_incompatible_shared(module)
15041540
with self.subTest(f'{module}: strict, isolated'):
1505-
self.check_compatible_isolated(module)
1541+
self.check_incompatible_isolated(module)
15061542

15071543
@unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module")
15081544
def test_multi_init_extension_compat(self):

Python/import.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2442,29 +2442,36 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file)
24422442

24432443
PyThreadState *tstate = _PyThreadState_GET();
24442444
mod = import_find_extension(tstate, name, path);
2445-
if (mod != NULL || PyErr_Occurred()) {
2446-
Py_DECREF(name);
2447-
Py_DECREF(path);
2448-
return mod;
2445+
if (mod != NULL) {
2446+
const char *name_buf = PyUnicode_AsUTF8(name);
2447+
assert(name_buf != NULL);
2448+
if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) {
2449+
Py_DECREF(mod);
2450+
mod = NULL;
2451+
}
2452+
goto finally;
2453+
}
2454+
else if (PyErr_Occurred()) {
2455+
goto finally;
24492456
}
24502457

24512458
if (file != NULL) {
24522459
fp = _Py_fopen_obj(path, "r");
24532460
if (fp == NULL) {
2454-
Py_DECREF(name);
2455-
Py_DECREF(path);
2456-
return NULL;
2461+
goto finally;
24572462
}
24582463
}
24592464
else
24602465
fp = NULL;
24612466

24622467
mod = _PyImport_LoadDynamicModuleWithSpec(spec, fp);
24632468

2464-
Py_DECREF(name);
2465-
Py_DECREF(path);
24662469
if (fp)
24672470
fclose(fp);
2471+
2472+
finally:
2473+
Py_DECREF(name);
2474+
Py_DECREF(path);
24682475
return mod;
24692476
}
24702477

Python/importdl.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "Python.h"
55
#include "pycore_call.h"
6+
#include "pycore_import.h"
67
#include "pycore_pystate.h"
78
#include "pycore_runtime.h"
89

@@ -206,6 +207,10 @@ _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp)
206207

207208
/* Fall back to single-phase init mechanism */
208209

210+
if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) {
211+
goto error;
212+
}
213+
209214
if (hook_prefix == nonascii_prefix) {
210215
/* don't allow legacy init for non-ASCII module names */
211216
PyErr_Format(

0 commit comments

Comments
 (0)