8000 Raise ImportError in subinterpreters for incompatible single-phase in… · python/cpython@1105a21 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1105a21

Browse files
Raise ImportError in subinterpreters for incompatible single-phase init extensions.
1 parent eb7d1ce commit 1105a21

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
@@ -1459,6 +1459,22 @@ def check_compatible_shared(self, name, *, strict=False):
14591459
out = os.read(r, 100)
14601460
self.assertEqual(out, b'okay')
14611461

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

1499+
def check_incompatible_isolated(self, name):
1500+
# Differences from check_compatible_isolated():
1501+
# * verify that import fails
1502+
# * "strict" is always True
1503+
_, out, err = script_helper.assert_python_ok('-c', textwrap.dedent(f'''
1504+
import _testcapi, sys
1505+
assert {name!r} not in sys.modules, {name!r}
1506+
ret = _testcapi.run_in_subinterp_with_config(
1507+
{self.import_script(name, "sys.stdout.fileno()")!r},
1508+
**{self.RUN_KWARGS},
1509+
check_multi_interp_extensions=True,
1510+
)
1511+
assert ret == 0, ret
1512+
'''))
1513+
self.assertEqual(err, b'')
1514+
self.assertEqual(
1515+
out.decode('utf-8'),
1516+
f'ImportError: module {name} does not support loading in subinterpreters',
1517+
)
1518+
14831519
def test_builtin_compat(self):
14841520
module = 'sys'
14851521
with self.subTest(f'{module}: not strict'):
@@ -1503,9 +1539,9 @@ def test_single_init_extension_compat(self):
15031539
with self.subTest(f'{module}: not strict'):
15041540
self.check_compatible_shared(module, strict=False)
15051541
with self.subTest(f'{module}: strict, shared'):
1506-
self.check_compatible_shared(module)
1542+
self.check_incompatible_shared(module)
15071543
with self.subTest(f'{module}: strict, isolated'):
1508-
self.check_compatible_isolated(module)
1544+
self.check_incompatible_isolated(module)
15091545

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

Python/import.c

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

23782378
PyThreadState *tstate = _PyThreadState_GET();
23792379
mod = import_find_extension(tstate, name, path);
2380-
if (mod != NULL || PyErr_Occurred()) {
2381-
Py_DECREF(name);
2382-
Py_DECREF(path);
2383-
return mod;
2380+
if (mod != NULL) {
2381+
const char *name_buf = PyUnicode_AsUTF8(name);
2382+
assert(name_buf != NULL);
2383+
if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) {
2384+
Py_DECREF(mod);
2385+
mod = NULL;
2386+
}
2387+
goto finally;
2388+
}
2389+
else if (PyErr_Occurred()) {
2390+
goto finally;
23842391
}
23852392

23862393
if (file != NULL) {
23872394
fp = _Py_fopen_obj(path, "r");
23882395
if (fp == NULL) {
2389-
Py_DECREF(name);
2390-
Py_DECREF(path);
2391-
return NULL;
2396+
goto finally;
23922397
}
23932398
}
23942399
else
23952400
fp = NULL;
23962401

23972402
mod = _PyImport_LoadDynamicModuleWithSpec(spec, fp);
23982403

2399-
Py_DECREF(name);
2400-
Py_DECREF(path);
24012404
if (fp)
24022405
fclose(fp);
2406+
2407+
finally:
2408+
Py_DECREF(name);
2409+
Py_DECREF(path);
24032410
return mod;
24042411
}
24052412

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

@@ -205,6 +206,10 @@ _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp)
205206

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

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

0 commit comments

Comments
 (0)
0