Skip to content

Commit 265fcc5

Browse files
bpo-31286, bpo-30024: Fixed stack usage in absolute imports with (#3217)
binding a submodule to a name.
1 parent ba7d736 commit 265fcc5

File tree

2 files changed

+33
-10
lines changed

2 files changed

+33
-10
lines changed

Lib/test/test_import/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,23 @@ def test_import_name_binding(self):
237237
import test.support as y
238238
self.assertIs(y, test.support, y.__name__)
239239

240+
def test_issue31286(self):
241+
# import in a 'finally' block resulted in SystemError
242+
try:
243+
x = ...
244+
finally:
245+
import test.support.script_helper as x
246+
247+
# import in a 'while' loop resulted in stack overflow
248+
i = 0
249+
while i < 10:
250+
import test.support.script_helper as x
251+
i += 1
252+
253+
# import in a 'for' loop resulted in segmentation fault
254+
for i in range(2):
255+
import test.support.script_helper as x
256+
240257
def test_failing_reload(self):
241258
# A failing reload should leave the module object in sys.modules.
242259
source = TESTFN + os.extsep + "py"

Python/compile.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2673,28 +2673,34 @@ compiler_import_as(struct compiler *c, identifier name, identifier asname)
26732673
If there is a dot in name, we need to split it and emit a
26742674
IMPORT_FROM for each name.
26752675
*/
2676-
Py_ssize_t dot = PyUnicode_FindChar(name, '.', 0,
2677-
PyUnicode_GET_LENGTH(name), 1);
2676+
Py_ssize_t len = PyUnicode_GET_LENGTH(name);
2677+
Py_ssize_t dot = PyUnicode_FindChar(name, '.', 0, len, 1);
26782678
if (dot == -2)
26792679
return 0;
26802680
if (dot != -1) {
26812681
/* Consume the base module name to get the first attribute */
2682-
Py_ssize_t pos = dot + 1;
2683-
while (dot != -1) {
2682+
while (1) {
2683+
Py_ssize_t pos = dot + 1;
26842684
PyObject *attr;
2685-
dot = PyUnicode_FindChar(name, '.', pos,
2686-
PyUnicode_GET_LENGTH(name), 1);
2685+
dot = PyUnicode_FindChar(name, '.', pos, len, 1);
26872686
if (dot == -2)
26882687
return 0;
2689-
attr = PyUnicode_Substring(name, pos,
2690-
(dot != -1) ? dot :
2691-
PyUnicode_GET_LENGTH(name));
2688+
attr = PyUnicode_Substring(name, pos, (dot != -1) ? dot : len);
26922689
if (!attr)
26932690
return 0;
26942691
ADDOP_O(c, IMPORT_FROM, attr, names);
26952692
Py_DECREF(attr);
2696-
pos = dot + 1;
2693+
if (dot == -1) {
2694+
break;
2695+
}
2696+
ADDOP(c, ROT_TWO);
2697+
ADDOP(c, POP_TOP);
26972698
}
2699+
if (!compiler_nameop(c, asname, Store)) {
2700+
return 0;
2701+
}
2702+
ADDOP(c, POP_TOP);
2703+
return 1;
26982704
}
26992705
return compiler_nameop(c, asname, Store);
27002706
}

0 commit comments

Comments
 (0)