Skip to content

Commit 223364f

Browse files
Yhg1smiss-islington
authored andcommitted
gh-158918: Reduce C stack usage of _PyModule_IsPossiblyShadowing. (GH-158919)
Reduce C stack usage of `_PyModule_IsPossiblyShadowing`, which could potentially cause stack overflows during module attribute access while deeply recursing in agressively optimized builds. (cherry picked from commit 53be7d4) Co-authored-by: T. Wouters <thomas@python.org>
1 parent 21238ec commit 223364f

2 files changed

Lines changed: 24 additions & 11 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Reduce C stack usage of ``_PyModule_IsPossiblyShadowing``, which could
2+
potentially cause stack overflows during module attribute access while
3+
deeply recursing in agressively optimized builds.

‎Objects/moduleobject.c‎

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,10 @@ _PyModuleSpec_GetFileOrigin(PyObject *spec, PyObject **p_origin)
922922
int
923923
_PyModule_IsPossiblyShadowing(PyObject *origin)
924924
{
925+
int result = 0;
926+
wchar_t *root = NULL;
927+
wchar_t *sys_path_0_buf = NULL;
928+
925929
// origin must be a unicode subtype
926930
// Returns 1 if the module at origin could be shadowing a module of the
927931
// same name later in the module search path. The condition we check is basically:
@@ -940,46 +944,52 @@ _PyModule_IsPossiblyShadowing(PyObject *origin)
940944
}
941945

942946
// root = os.path.dirname(origin.removesuffix(os.sep + "__init__.py"))
943-
wchar_t root[MAXPATHLEN + 1];
944-
Py_ssize_t size = PyUnicode_AsWideChar(origin, root, MAXPATHLEN);
945-
if (size < 0) {
947+
root = PyUnicode_AsWideCharString(origin, NULL);
948+
if (root == NULL) {
946949
return -1;
947950
}
948-
assert(size <= MAXPATHLEN);
949-
root[size] = L'\0';
950951

951952
wchar_t *sep = wcsrchr(root, SEP);
952953
if (sep == NULL) {
953-
return 0;
954+
goto done;
954955
}
955956
// If it's a package then we need to look one directory further up
956957
if (wcscmp(sep + 1, L"__init__.py") == 0) {
957958
*sep = L'\0';
958959
sep = wcsrchr(root, SEP);
959960
if (sep == NULL) {
960-
return 0;
961+
goto done;
961962
}
962963
}
963964
*sep = L'\0';
964965

965966
// sys.path[0] or os.getcwd()
966967
wchar_t *sys_path_0 = config->sys_path_0;
967968
if (!sys_path_0) {
968-
return 0;
969+
goto done;
969970
}
970971

971-
wchar_t sys_path_0_buf[MAXPATHLEN];
972972
if (sys_path_0[0] == L'\0') {
973973
// if sys.path[0] == "", treat it as if it were the current directory
974+
sys_path_0_buf = PyMem_Malloc(MAXPATHLEN * sizeof(wchar_t));
975+
if (sys_path_0_buf == NULL) {
976+
PyErr_NoMemory();
977+
result = -1;
978+
goto done;
979+
}
974980
if (!_Py_wgetcwd(sys_path_0_buf, MAXPATHLEN)) {
975981
// If we failed to getcwd, don't raise an exception and instead
976982
// let the caller proceed assuming no shadowing
977-
return 0;
983+
goto done;
978984
}
979985
sys_path_0 = sys_path_0_buf;
980986
}
981987

982-
int result = wcscmp(sys_path_0, root) == 0;
988+
result = (wcscmp(sys_path_0, root) == 0);
989+
990+
done:
991+
PyMem_Free(root);
992+
PyMem_Free(sys_path_0_buf);
983993
return result;
984994
}
985995

0 commit comments

Comments
 (0)