Skip to content

bpo-38234: Cleanup getpath.c #16367

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Lib/test/pythoninfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,13 @@ def collect_windows(info_add):
res = bool(RtlAreLongPathsEnabled())
info_add('windows.RtlAreLongPathsEnabled', res)

try:
import _winapi
dll_path = _winapi.GetModuleFileName(sys.dllhandle)
info_add('windows.dll_path', dll_path)
except (ImportError, AttributeError):
pass


def collect_info(info):
error = False
Expand Down
189 changes: 116 additions & 73 deletions Modules/getpath.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,12 +370,15 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
const wchar_t *argv0_path,
wchar_t *prefix, size_t prefix_len, int *found)
{
wchar_t path[MAXPATHLEN+1];
memset(path, 0, sizeof(path));
size_t path_len = Py_ARRAY_LENGTH(path);

PyStatus status;
size_t n;
wchar_t *vpath;

/* If PYTHONHOME is set, we believe it unconditionally */
if (pathconfig->home) {
/* Path: <home> / <lib_python> */
if (safe_wcscpy(prefix, pathconfig->home, prefix_len) < 0) {
return PATHLEN_ERR();
}
Expand All @@ -387,27 +390,25 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
if (_PyStatus_EXCEPTION(status)) {
return status;
}
status = joinpath(prefix, LANDMARK, prefix_len);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
*found = 1;
return _PyStatus_OK();
}

/* Check to see if argv[0] is in the build directory */
if (safe_wcscpy(prefix, argv0_path, prefix_len) < 0) {
if (safe_wcscpy(path, argv0_path, path_len) < 0) {
return PATHLEN_ERR();
}
status = joinpath(prefix, L"Modules/Setup.local", prefix_len);
status = joinpath(path, L"Modules/Setup.local", path_len);
if (_PyStatus_EXCEPTION(status)) {
return status;
}

if (isfile(prefix)) {
/* Check VPATH to see if argv0_path is in the build directory. */
vpath = Py_DecodeLocale(VPATH, NULL);
if (isfile(path)) {
/* Check VPATH to see if argv0_path is in the build directory.
VPATH can be empty. */
wchar_t *vpath = Py_DecodeLocale(VPATH, NULL);
if (vpath != NULL) {
/* Path: <argv0_path> / <vpath> / Lib / LANDMARK */
if (safe_wcscpy(prefix, argv0_path, prefix_len) < 0) {
return PATHLEN_ERR();
}
Expand All @@ -428,6 +429,7 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,

if (ismodule(prefix, prefix_len)) {
*found = -1;
reduce(prefix);
return _PyStatus_OK();
}
}
Expand All @@ -440,7 +442,8 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
}

do {
n = wcslen(prefix);
/* Path: <argv0_path or substring> / <lib_python> / LANDMARK */
size_t n = wcslen(prefix);
status = joinpath(prefix, calculate->lib_python, prefix_len);
if (_PyStatus_EXCEPTION(status)) {
return status;
Expand All @@ -452,13 +455,15 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,

if (ismodule(prefix, prefix_len)) {
*found = 1;
reduce(prefix);
return _PyStatus_OK();
}
prefix[n] = L'\0';
reduce(prefix);
} while (prefix[0]);

/* Look at configure's PREFIX */
/* Look at configure's PREFIX.
Path: <PREFIX macro> / <lib_python> / LANDMARK */
if (safe_wcscpy(prefix, calculate->prefix, prefix_len) < 0) {
return PATHLEN_ERR();
}
Expand All @@ -473,6 +478,7 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,

if (ismodule(prefix, prefix_len)) {
*found = 1;
reduce(prefix);
return _PyStatus_OK();
}

Expand Down Expand Up @@ -509,9 +515,6 @@ calculate_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
return status;
}
}
else {
reduce(prefix);
}
return _PyStatus_OK();
}

Expand Down Expand Up @@ -546,6 +549,67 @@ calculate_set_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
}


static PyStatus
calculate_pybuilddir(const wchar_t *argv0_path,
wchar_t *exec_prefix, size_t exec_prefix_len,
int *found)
{
PyStatus status;

wchar_t filename[MAXPATHLEN+1];
memset(filename, 0, sizeof(filename));
size_t filename_len = Py_ARRAY_LENGTH(filename);

/* Check to see if argv[0] is in the build directory. "pybuilddir.txt"
is written by setup.py and contains the relative path to the location
of shared library modules.

Filename: <argv0_path> / "pybuilddir.txt" */
if (safe_wcscpy(filename, argv0_path, filename_len) < 0) {
return PATHLEN_ERR();
}
status = joinpath(filename, L"pybuilddir.txt", filename_len);
if (_PyStatus_EXCEPTION(status)) {
return status;
}

if (!isfile(filename)) {
return _PyStatus_OK();
}

FILE *fp = _Py_wfopen(filename, L"rb");
if (fp == NULL) {
errno = 0;
return _PyStatus_OK();
}

char buf[MAXPATHLEN + 1];
size_t n = fread(buf, 1, Py_ARRAY_LENGTH(buf) - 1, fp);
buf[n] = '\0';
fclose(fp);

size_t dec_len;
wchar_t *pybuilddir = _Py_DecodeUTF8_surrogateescape(buf, n, &dec_len);
if (!pybuilddir) {
return DECODE_LOCALE_ERR("pybuilddir.txt", dec_len);
}

/* Path: <argv0_path> / <pybuilddir content> */
if (safe_wcscpy(exec_prefix, argv0_path, exec_prefix_len) < 0) {
PyMem_RawFree(pybuilddir);
return PATHLEN_ERR();
}
status = joinpath(exec_prefix, pybuilddir, exec_prefix_len);
PyMem_RawFree(pybuilddir);
if (_PyStatus_EXCEPTION(status)) {
return status;
}

*found = -1;
return _PyStatus_OK();
}


/* search_for_exec_prefix requires that argv0_path be no more than
MAXPATHLEN bytes long.
*/
Expand All @@ -556,10 +620,10 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
int *found)
{
PyStatus status;
size_t n;

/* If PYTHONHOME is set, we believe it unconditionally */
if (pathconfig->home) {
/* Path: <home> / <lib_python> / "lib-dynload" */
wchar_t *delim = wcschr(pathconfig->home, DELIM);
if (delim) {
if (safe_wcscpy(exec_prefix, delim+1, exec_prefix_len) < 0) {
Expand All @@ -583,47 +647,15 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
return _PyStatus_OK();
}

/* Check to see if argv[0] is in the build directory. "pybuilddir.txt"
is written by setup.py and contains the relative path to the location
of shared library modules. */
if (safe_wcscpy(exec_prefix, argv0_path, exec_prefix_len) < 0) {
return PATHLEN_ERR();
}
status = joinpath(exec_prefix, L"pybuilddir.txt", exec_prefix_len);
/* Check for pybuilddir.txt */
assert(*found == 0);
status = calculate_pybuilddir(argv0_path, exec_prefix, exec_prefix_len,
found);
if (_PyStatus_EXCEPTION(status)) {
return status;
}

if (isfile(exec_prefix)) {
FILE *f = _Py_wfopen(exec_prefix, L"rb");
if (f == NULL) {
errno = 0;
}
else {
char buf[MAXPATHLEN + 1];
n = fread(buf, 1, Py_ARRAY_LENGTH(buf) - 1, f);
buf[n] = '\0';
fclose(f);

wchar_t *pybuilddir;
size_t dec_len;
pybuilddir = _Py_DecodeUTF8_surrogateescape(buf, n, &dec_len);
if (!pybuilddir) {
return DECODE_LOCALE_ERR("pybuilddir.txt", dec_len);
}

if (safe_wcscpy(exec_prefix, argv0_path, exec_prefix_len) < 0) {
return PATHLEN_ERR();
}
status = joinpath(exec_prefix, pybuilddir, exec_prefix_len);
PyMem_RawFree(pybuilddir );
if (_PyStatus_EXCEPTION(status)) {
return status;
}

*found = -1;
return _PyStatus_OK();
}
if (*found) {
return _PyStatus_OK();
}

/* Search from argv0_path, until root is found */
Expand All @@ -633,7 +665,8 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
}

do {
n = wcslen(exec_prefix);
/* Path: <argv0_path or substring> / <lib_python> / "lib-dynload" */
size_t n = wcslen(exec_prefix);
status = joinpath(exec_prefix, calculate->lib_python, exec_prefix_len);
if (_PyStatus_EXCEPTION(status)) {
return status;
Expand All @@ -650,7 +683,9 @@ search_for_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
reduce(exec_prefix);
} while (exec_prefix[0]);

/* Look at configure's EXEC_PREFIX */
/* Look at configure's EXEC_PREFIX.

Path: <EXEC_PREFIX macro> / <lib_python> / "lib-dynload" */
if (safe_wcscpy(exec_prefix, calculate->exec_prefix, exec_prefix_len) < 0) {
return PATHLEN_ERR();
}
Expand Down Expand Up @@ -962,43 +997,49 @@ calculate_read_pyenv(PyCalculatePath *calculate,
wchar_t *argv0_path, size_t argv0_path_len)
{
PyStatus status;
wchar_t tmpbuffer[MAXPATHLEN+1];
const size_t buflen = Py_ARRAY_LENGTH(tmpbuffer);
wchar_t *env_cfg = L"pyvenv.cfg";
const wchar_t *env_cfg = L"pyvenv.cfg";
FILE *env_file;

if (safe_wcscpy(tmpbuffer, argv0_path, buflen) < 0) {
wchar_t filename[MAXPATHLEN+1];
const size_t filename_len = Py_ARRAY_LENGTH(filename);
memset(filename, 0, sizeof(filename));

/* Filename: <argv0_path_len> / "pyvenv.cfg" */
if (safe_wcscpy(filename, argv0_path, filename_len) < 0) {
return PATHLEN_ERR();
}

status = joinpath(tmpbuffer, env_cfg, buflen);
status = joinpath(filename, env_cfg, filename_len);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
env_file = _Py_wfopen(tmpbuffer, L"r");
env_file = _Py_wfopen(filename, L"r");
if (env_file == NULL) {
errno = 0;

reduce(tmpbuffer);
reduce(tmpbuffer);
status = joinpath(tmpbuffer, env_cfg, buflen);
/* Filename: <basename(basename(argv0_path_len))> / "pyvenv.cfg" */
reduce(filename);
reduce(filename);
status = joinpath(filename, env_cfg, filename_len);
if (_PyStatus_EXCEPTION(status)) {
return status;
}

env_file = _Py_wfopen(tmpbuffer, L"r");
env_file = _Py_wfopen(filename, L"r");
if (env_file == NULL) {
errno = 0;
return _PyStatus_OK();
}
}

if (env_file == NULL) {
return _PyStatus_OK();
}

/* Look for a 'home' variable and set argv0_path to it, if found */
if (_Py_FindEnvConfigValue(env_file, L"home", tmpbuffer, buflen)) {
if (safe_wcscpy(argv0_path, tmpbuffer, argv0_path_len) < 0) {
wchar_t home[MAXPATHLEN+1];
memset(home, 0, sizeof(home));

if (_Py_FindEnvConfigValue(env_file, L"home",
home, Py_ARRAY_LENGTH(home))) {
if (safe_wcscpy(argv0_path, home, argv0_path_len) < 0) {
fclose(env_file);
return PATHLEN_ERR();
}
}
Expand Down Expand Up @@ -1200,6 +1241,8 @@ calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
return status;
}

/* If a pyvenv.cfg configure file is found,
argv0_path is overriden with its 'home' variable. */
status = calculate_read_pyenv(calculate,
argv0_path, Py_ARRAY_LENGTH(argv0_path));
if (_PyStatus_EXCEPTION(status)) {
Expand Down
30 changes: 15 additions & 15 deletions PC/getpathp.c
Original file line number Diff line number Diff line change
Expand Up @@ -757,34 +757,34 @@ static void
calculate_pyvenv_file(PyCalculatePath *calculate,
wchar_t *argv0_path, size_t argv0_path_len)
{
wchar_t envbuffer[MAXPATHLEN+1];
wchar_t filename[MAXPATHLEN+1];
const wchar_t *env_cfg = L"pyvenv.cfg";

wcscpy_s(envbuffer, MAXPATHLEN+1, argv0_path);
join(envbuffer, env_cfg);
/* Filename: <argv0_path_len> / "pyvenv.cfg" */
wcscpy_s(filename, MAXPATHLEN+1, argv0_path);
join(filename, env_cfg);

FILE *env_file = _Py_wfopen(envbuffer, L"r");
FILE *env_file = _Py_wfopen(filename, L"r");
if (env_file == NULL) {
errno = 0;

reduce(envbuffer);
reduce(envbuffer);
join(envbuffer, env_cfg);
/* Filename: <basename(basename(argv0_path_len))> / "pyvenv.cfg" */
reduce(filename);
reduce(filename);
join(filename, env_cfg);

env_file = _Py_wfopen(envbuffer, L"r");
env_file = _Py_wfopen(filename, L"r");
if (env_file == NULL) {
errno = 0;
return;
}
}

if (env_file == NULL) {
return;
}

/* Look for a 'home' variable and set argv0_path to it, if found */
wchar_t tmpbuffer[MAXPATHLEN+1];
if (_Py_FindEnvConfigValue(env_file, L"home", tmpbuffer, MAXPATHLEN)) {
wcscpy_s(argv0_path, argv0_path_len, tmpbuffer);
wchar_t home[MAXPATHLEN+1];
if (_Py_FindEnvConfigValue(env_file, L"home",
home, Py_ARRAY_LENGTH(home))) {
wcscpy_s(argv0_path, argv0_path_len, home);
}
fclose(env_file);
}
Expand Down