Skip to content

Commit 53be7d4

Browse files
authored
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.
1 parent a6e6361 commit 53be7d4

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
@@ -1238,6 +1238,10 @@ _PyModuleSpec_GetFileOrigin(PyObject *spec, PyObject **p_origin)
12381238
int
12391239
_PyModule_IsPossiblyShadowing(PyObject *origin)
12401240
{
1241+
int result = 0;
1242+
wchar_t *root = NULL;
1243+
wchar_t *sys_path_0_buf = NULL;
1244+
12411245
// origin must be a unicode subtype
12421246
// Returns 1 if the module at origin could be shadowing a module of the
12431247
// same name later in the module search path. The condition we check is basically:
@@ -1256,46 +1260,52 @@ _PyModule_IsPossiblyShadowing(PyObject *origin)
12561260
}
12571261

12581262
// root = os.path.dirname(origin.removesuffix(os.sep + "__init__.py"))
1259-
wchar_t root[MAXPATHLEN + 1];
1260-
Py_ssize_t size = PyUnicode_AsWideChar(origin, root, MAXPATHLEN);
1261-
if (size < 0) {
1263+
root = PyUnicode_AsWideCharString(origin, NULL);
1264+
if (root == NULL) {
12621265
return -1;
12631266
}
1264-
assert(size <= MAXPATHLEN);
1265-
root[size] = L'\0';
12661267

12671268
wchar_t *sep = wcsrchr(root, SEP);
12681269
if (sep == NULL) {
1269-
return 0;
1270+
goto done;
12701271
}
12711272
// If it's a package then we need to look one directory further up
12721273
if (wcscmp(sep + 1, L"__init__.py") == 0) {
12731274
*sep = L'\0';
12741275
sep = wcsrchr(root, SEP);
12751276
if (sep == NULL) {
1276-
return 0;
1277+
goto done;
12771278
}
12781279
}
12791280
*sep = L'\0';
12801281

12811282
// sys.path[0] or os.getcwd()
12821283
wchar_t *sys_path_0 = config->sys_path_0;
12831284
if (!sys_path_0) {
1284-
return 0;
1285+
goto done;
12851286
}
12861287

1287-
wchar_t sys_path_0_buf[MAXPATHLEN];
12881288
if (sys_path_0[0] == L'\0') {
12891289
// if sys.path[0] == "", treat it as if it were the current directory
1290+
sys_path_0_buf = PyMem_Malloc(MAXPATHLEN * sizeof(wchar_t));
1291+
if (sys_path_0_buf == NULL) {
1292+
PyErr_NoMemory();
1293+
result = -1;
1294+
goto done;
1295+
}
12901296
if (!_Py_wgetcwd(sys_path_0_buf, MAXPATHLEN)) {
12911297
// If we failed to getcwd, don't raise an exception and instead
12921298
// let the caller proceed assuming no shadowing
1293-
return 0;
1299+
goto done;
12941300
}
12951301
sys_path_0 = sys_path_0_buf;
12961302
}
12971303

1298-
int result = wcscmp(sys_path_0, root) == 0;
1304+
result = (wcscmp(sys_path_0, root) == 0);
1305+
1306+
done:
1307+
PyMem_Free(root);
1308+
PyMem_Free(sys_path_0_buf);
12991309
return result;
13001310
}
13011311

0 commit comments

Comments
 (0)