Commit c02b41b1 authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

bpo-38353: getpath.c: allocates strings on the heap (GH-16585)

* _Py_FindEnvConfigValue() now returns a string allocated
  by PyMem_RawMalloc().
* calculate_init() now decodes VPATH macro.
* Add calculate_open_pyenv() function.
* Add substring() and joinpath2() functions.

* Fix add_exe_suffix()

And a few cleanup changes.
parent abd7cd85
...@@ -56,11 +56,10 @@ extern PyStatus _PyPathConfig_Calculate( ...@@ -56,11 +56,10 @@ extern PyStatus _PyPathConfig_Calculate(
extern int _PyPathConfig_ComputeSysPath0( extern int _PyPathConfig_ComputeSysPath0(
const PyWideStringList *argv, const PyWideStringList *argv,
PyObject **path0); PyObject **path0);
extern int _Py_FindEnvConfigValue( extern PyStatus _Py_FindEnvConfigValue(
FILE *env_file, FILE *env_file,
const wchar_t *key, const wchar_t *key,
wchar_t *value, wchar_t **value_p);
size_t value_size);
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
extern wchar_t* _Py_GetDLLPath(void); extern wchar_t* _Py_GetDLLPath(void);
......
...@@ -113,6 +113,8 @@ extern "C" { ...@@ -113,6 +113,8 @@ extern "C" {
#define LANDMARK L"os.py" #define LANDMARK L"os.py"
#endif #endif
#define BUILD_LANDMARK L"Modules/Setup.local"
#define DECODE_LOCALE_ERR(NAME, LEN) \ #define DECODE_LOCALE_ERR(NAME, LEN) \
((LEN) == (size_t)-2) \ ((LEN) == (size_t)-2) \
? _PyStatus_ERR("cannot decode " NAME) \ ? _PyStatus_ERR("cannot decode " NAME) \
...@@ -126,6 +128,7 @@ typedef struct { ...@@ -126,6 +128,7 @@ typedef struct {
wchar_t *pythonpath_macro; /* PYTHONPATH macro */ wchar_t *pythonpath_macro; /* PYTHONPATH macro */
wchar_t *prefix_macro; /* PREFIX macro */ wchar_t *prefix_macro; /* PREFIX macro */
wchar_t *exec_prefix_macro; /* EXEC_PREFIX macro */ wchar_t *exec_prefix_macro; /* EXEC_PREFIX macro */
wchar_t *vpath_macro; /* VPATH macro */
wchar_t *lib_python; /* "lib/pythonX.Y" */ wchar_t *lib_python; /* "lib/pythonX.Y" */
...@@ -222,7 +225,12 @@ isdir(const wchar_t *filename) ...@@ -222,7 +225,12 @@ isdir(const wchar_t *filename)
/* Add a path component, by appending stuff to buffer. /* Add a path component, by appending stuff to buffer.
buflen: 'buffer' length in characters including trailing NUL. */ buflen: 'buffer' length in characters including trailing NUL.
If path2 is empty:
- if path doesn't end with SEP and is not empty, add SEP to path
- otherwise, do nothing. */
static PyStatus static PyStatus
joinpath(wchar_t *path, const wchar_t *path2, size_t path_len) joinpath(wchar_t *path, const wchar_t *path2, size_t path_len)
{ {
...@@ -252,6 +260,48 @@ joinpath(wchar_t *path, const wchar_t *path2, size_t path_len) ...@@ -252,6 +260,48 @@ joinpath(wchar_t *path, const wchar_t *path2, size_t path_len)
} }
static wchar_t*
substring(const wchar_t *str, size_t len)
{
wchar_t *substr = PyMem_RawMalloc((len + 1) * sizeof(wchar_t));
if (substr == NULL) {
return NULL;
}
if (len) {
memcpy(substr, str, len * sizeof(wchar_t));
}
substr[len] = L'\0';
return substr;
}
static wchar_t*
joinpath2(const wchar_t *path, const wchar_t *path2)
{
if (_Py_isabs(path2)) {
return _PyMem_RawWcsdup(path2);
}
size_t len = wcslen(path);
int add_sep = (len > 0 && path[len - 1] != SEP);
len += add_sep;
len += wcslen(path2);
wchar_t *new_path = PyMem_RawMalloc((len + 1) * sizeof(wchar_t));
if (new_path == NULL) {
return NULL;
}
wcscpy(new_path, path);
if (add_sep) {
wcscat(new_path, separator);
}
wcscat(new_path, path2);
return new_path;
}
static inline int static inline int
safe_wcscpy(wchar_t *dst, const wchar_t *src, size_t n) safe_wcscpy(wchar_t *dst, const wchar_t *src, size_t n)
{ {
...@@ -297,20 +347,22 @@ copy_absolute(wchar_t *abs_path, const wchar_t *path, size_t abs_path_len) ...@@ -297,20 +347,22 @@ copy_absolute(wchar_t *abs_path, const wchar_t *path, size_t abs_path_len)
/* path_len: path length in characters including trailing NUL */ /* path_len: path length in characters including trailing NUL */
static PyStatus static PyStatus
absolutize(wchar_t *path, size_t path_len) absolutize(wchar_t **path_p)
{ {
if (_Py_isabs(path)) { assert(!_Py_isabs(*path_p));
return _PyStatus_OK();
}
wchar_t abs_path[MAXPATHLEN+1]; wchar_t abs_path[MAXPATHLEN+1];
wchar_t *path = *path_p;
PyStatus status = copy_absolute(abs_path, path, Py_ARRAY_LENGTH(abs_path)); PyStatus status = copy_absolute(abs_path, path, Py_ARRAY_LENGTH(abs_path));
if (_PyStatus_EXCEPTION(status)) { if (_PyStatus_EXCEPTION(status)) {
return status; return status;
} }
if (safe_wcscpy(path, abs_path, path_len) < 0) { PyMem_RawFree(*path_p);
return PATHLEN_ERR(); *path_p = _PyMem_RawWcsdup(abs_path);
if (*path_p == NULL) {
return _PyStatus_NO_MEMORY();
} }
return _PyStatus_OK(); return _PyStatus_OK();
} }
...@@ -320,33 +372,33 @@ absolutize(wchar_t *path, size_t path_len) ...@@ -320,33 +372,33 @@ absolutize(wchar_t *path, size_t path_len)
static PyStatus static PyStatus
ismodule(const wchar_t *path, int *result) ismodule(const wchar_t *path, int *result)
{ {
wchar_t filename[MAXPATHLEN+1]; wchar_t *filename = joinpath2(path, LANDMARK);
size_t filename_len = Py_ARRAY_LENGTH(filename); if (filename == NULL) {
return _PyStatus_NO_MEMORY();
if (safe_wcscpy(filename, path, filename_len) < 0) {
return PATHLEN_ERR();
}
PyStatus status = joinpath(filename, LANDMARK, filename_len);
if (_PyStatus_EXCEPTION(status)) {
return status;
} }
if (isfile(filename)) { if (isfile(filename)) {
PyMem_RawFree(filename);
*result = 1; *result = 1;
return _PyStatus_OK(); return _PyStatus_OK();
} }
/* Check for the compiled version of prefix. */ /* Check for the compiled version of prefix. */
if (wcslen(filename) + 2 <= filename_len) { size_t len = wcslen(filename);
wcscat(filename, L"c"); wchar_t *pyc = PyMem_RawMalloc((len + 2) * sizeof(wchar_t));
if (isfile(filename)) { if (pyc == NULL) {
*result = 1; PyMem_RawFree(filename);
return _PyStatus_OK(); return _PyStatus_NO_MEMORY();
}
} }
*result = 0; memcpy(pyc, filename, len * sizeof(wchar_t));
pyc[len] = L'c';
pyc[len + 1] = L'\0';
*result = isfile(pyc);
PyMem_RawFree(filename);
PyMem_RawFree(pyc);
return _PyStatus_OK(); return _PyStatus_OK();
} }
...@@ -358,24 +410,32 @@ ismodule(const wchar_t *path, int *result) ...@@ -358,24 +410,32 @@ ismodule(const wchar_t *path, int *result)
/* pathlen: 'path' length in characters including trailing NUL */ /* pathlen: 'path' length in characters including trailing NUL */
static PyStatus static PyStatus
add_exe_suffix(wchar_t *path, size_t pathlen) add_exe_suffix(wchar_t **progpath_p)
{ {
wchar_t *progpath = *progpath_p;
/* Check for already have an executable suffix */ /* Check for already have an executable suffix */
size_t n = wcslen(path); size_t n = wcslen(progpath);
size_t s = wcslen(EXE_SUFFIX); size_t s = wcslen(EXE_SUFFIX);
if (wcsncasecmp(EXE_SUFFIX, path + n - s, s) == 0) { if (wcsncasecmp(EXE_SUFFIX, progpath + n - s, s) == 0) {
return _PyStatus_OK(); return _PyStatus_OK();
} }
if (n + s >= pathlen) { wchar_t *progpath2 = PyMem_RawMalloc((n + s + 1) * sizeof(wchar_t));
return PATHLEN_ERR(); if (progpath2 == NULL) {
return _PyStatus_NO_MEMORY();
} }
wcsncpy(path + n, EXE_SUFFIX, s);
path[n + s] = '\0';
if (!isxfile(path)) { memcpy(progpath2, progpath, n * sizeof(wchar_t));
/* Path that added suffix is invalid: truncate (remove suffix) */ memcpy(progpath2 + n, EXE_SUFFIX, s * sizeof(wchar_t));
path[n] = '\0'; progpath2[n+s] = L'\0';
if (isxfile(progpath2)) {
PyMem_RawFree(*progpath_p);
*progpath_p = progpath2;
}
else {
PyMem_RawFree(progpath2);
} }
return _PyStatus_OK(); return _PyStatus_OK();
} }
...@@ -389,10 +449,6 @@ static PyStatus ...@@ -389,10 +449,6 @@ static PyStatus
search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig, search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
wchar_t *prefix, size_t prefix_len, int *found) 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; PyStatus status;
/* If PYTHONHOME is set, we believe it unconditionally */ /* If PYTHONHOME is set, we believe it unconditionally */
...@@ -413,44 +469,46 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig, ...@@ -413,44 +469,46 @@ search_for_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
return _PyStatus_OK(); return _PyStatus_OK();
} }
/* Check to see if argv[0] is in the build directory */ /* Check to see if argv0_path is in the build directory
if (safe_wcscpy(path, calculate->argv0_path, path_len) < 0) {
return PATHLEN_ERR(); Path: <argv0_path> / <BUILD_LANDMARK define> */
} wchar_t *path = joinpath2(calculate->argv0_path, BUILD_LANDMARK);
status = joinpath(path, L"Modules/Setup.local", path_len); if (path == NULL) {
if (_PyStatus_EXCEPTION(status)) { return _PyStatus_NO_MEMORY();
return status;
} }
if (isfile(path)) { int is_build_dir = isfile(path);
/* Check VPATH to see if argv0_path is in the build directory. PyMem_RawFree(path);
VPATH can be empty. */
wchar_t *vpath = Py_DecodeLocale(VPATH, NULL);
if (vpath != NULL) {
/* Path: <argv0_path> / <vpath> / Lib / LANDMARK */
if (safe_wcscpy(prefix, calculate->argv0_path, prefix_len) < 0) {
return PATHLEN_ERR();
}
status = joinpath(prefix, vpath, prefix_len);
PyMem_RawFree(vpath);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
status = joinpath(prefix, L"Lib", prefix_len); if (is_build_dir) {
if (_PyStatus_EXCEPTION(status)) { /* argv0_path is the build directory (BUILD_LANDMARK exists),
return status; now also check LANDMARK using ismodule(). */
}
int module; /* Path: <argv0_path> / <VPATH macro> / Lib */
status = ismodule(prefix, &module); /* or if VPATH is empty: <argv0_path> / Lib */
if (_PyStatus_EXCEPTION(status)) { if (safe_wcscpy(prefix, calculate->argv0_path, prefix_len) < 0) {
return status; return PATHLEN_ERR();
} }
if (module) {
*found = -1; status = joinpath(prefix, calculate->vpath_macro, prefix_len);
return _PyStatus_OK(); if (_PyStatus_EXCEPTION(status)) {
} return status;
}
status = joinpath(prefix, L"Lib", prefix_len);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
int module;
status = ismodule(prefix, &module);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
if (module) {
/* BUILD_LANDMARK and LANDMARK found */
*found = -1;
return _PyStatus_OK();
} }
} }
...@@ -527,16 +585,14 @@ calculate_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig) ...@@ -527,16 +585,14 @@ calculate_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
fprintf(stderr, fprintf(stderr,
"Could not find platform independent libraries <prefix>\n"); "Could not find platform independent libraries <prefix>\n");
} }
if (safe_wcscpy(prefix, calculate->prefix_macro, prefix_len) < 0) {
return PATHLEN_ERR(); calculate->prefix = joinpath2(calculate->prefix_macro,
} calculate->lib_python);
status = joinpath(prefix, calculate->lib_python, prefix_len); }
if (_PyStatus_EXCEPTION(status)) { else {
return status; calculate->prefix = _PyMem_RawWcsdup(prefix);
}
} }
calculate->prefix = _PyMem_RawWcsdup(prefix);
if (calculate->prefix == NULL) { if (calculate->prefix == NULL) {
return _PyStatus_NO_MEMORY(); return _PyStatus_NO_MEMORY();
} }
...@@ -553,26 +609,32 @@ calculate_set_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig) ...@@ -553,26 +609,32 @@ calculate_set_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
* return the compiled-in defaults instead. * return the compiled-in defaults instead.
*/ */
if (calculate->prefix_found > 0) { if (calculate->prefix_found > 0) {
wchar_t prefix[MAXPATHLEN+1]; wchar_t *prefix = _PyMem_RawWcsdup(calculate->prefix);
memset(prefix, 0, sizeof(prefix)); if (prefix == NULL) {
return _PyStatus_NO_MEMORY();
wcscpy(prefix, calculate->prefix); }
reduce(prefix); reduce(prefix);
reduce(prefix); reduce(prefix);
/* The prefix is the root directory, but reduce() chopped if (prefix[0]) {
* off the "/". */ pathconfig->prefix = prefix;
if (!prefix[0]) { }
wcscpy(prefix, separator); else {
PyMem_RawFree(prefix);
/* The prefix is the root directory, but reduce() chopped
off the "/". */
pathconfig->prefix = _PyMem_RawWcsdup(separator);
if (pathconfig->prefix == NULL) {
return _PyStatus_NO_MEMORY();
}
} }
pathconfig->prefix = _PyMem_RawWcsdup(prefix);
} }
else { else {
pathconfig->prefix = _PyMem_RawWcsdup(calculate->prefix_macro); pathconfig->prefix = _PyMem_RawWcsdup(calculate->prefix_macro);
} if (pathconfig->prefix == NULL) {
return _PyStatus_NO_MEMORY();
if (pathconfig->prefix == NULL) { }
return _PyStatus_NO_MEMORY();
} }
return _PyStatus_OK(); return _PyStatus_OK();
} }
...@@ -585,28 +647,23 @@ calculate_pybuilddir(const wchar_t *argv0_path, ...@@ -585,28 +647,23 @@ calculate_pybuilddir(const wchar_t *argv0_path,
{ {
PyStatus status; 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" /* 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 is written by setup.py and contains the relative path to the location
of shared library modules. of shared library modules.
Filename: <argv0_path> / "pybuilddir.txt" */ Filename: <argv0_path> / "pybuilddir.txt" */
if (safe_wcscpy(filename, argv0_path, filename_len) < 0) { wchar_t *filename = joinpath2(argv0_path, L"pybuilddir.txt");
return PATHLEN_ERR(); if (filename == NULL) {
} return _PyStatus_NO_MEMORY();
status = joinpath(filename, L"pybuilddir.txt", filename_len);
if (_PyStatus_EXCEPTION(status)) {
return status;
} }
if (!isfile(filename)) { if (!isfile(filename)) {
PyMem_RawFree(filename);
return _PyStatus_OK(); return _PyStatus_OK();
} }
FILE *fp = _Py_wfopen(filename, L"rb"); FILE *fp = _Py_wfopen(filename, L"rb");
PyMem_RawFree(filename);
if (fp == NULL) { if (fp == NULL) {
errno = 0; errno = 0;
return _PyStatus_OK(); return _PyStatus_OK();
...@@ -756,19 +813,19 @@ calculate_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig) ...@@ -756,19 +813,19 @@ calculate_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
fprintf(stderr, fprintf(stderr,
"Could not find platform dependent libraries <exec_prefix>\n"); "Could not find platform dependent libraries <exec_prefix>\n");
} }
if (safe_wcscpy(exec_prefix, calculate->exec_prefix_macro, exec_prefix_len) < 0) {
return PATHLEN_ERR(); calculate->exec_prefix = joinpath2(calculate->exec_prefix_macro,
} L"lib/lib-dynload");
status = joinpath(exec_prefix, L"lib/lib-dynload", exec_prefix_len); if (calculate->exec_prefix == NULL) {
if (_PyStatus_EXCEPTION(status)) { return _PyStatus_NO_MEMORY();
return status;
} }
} }
else {
/* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */ /* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */
calculate->exec_prefix = _PyMem_RawWcsdup(exec_prefix); calculate->exec_prefix = _PyMem_RawWcsdup(exec_prefix);
if (calculate->exec_prefix == NULL) { if (calculate->exec_prefix == NULL) {
return _PyStatus_NO_MEMORY(); return _PyStatus_NO_MEMORY();
}
} }
return _PyStatus_OK(); return _PyStatus_OK();
} }
...@@ -779,63 +836,71 @@ calculate_set_exec_prefix(PyCalculatePath *calculate, ...@@ -779,63 +836,71 @@ calculate_set_exec_prefix(PyCalculatePath *calculate,
_PyPathConfig *pathconfig) _PyPathConfig *pathconfig)
{ {
if (calculate->exec_prefix_found > 0) { if (calculate->exec_prefix_found > 0) {
wchar_t exec_prefix[MAXPATHLEN+1]; wchar_t *exec_prefix = _PyMem_RawWcsdup(calculate->exec_prefix);
memset(exec_prefix, 0, sizeof(exec_prefix)); if (exec_prefix == NULL) {
return _PyStatus_NO_MEMORY();
wcscpy(exec_prefix, calculate->exec_prefix); }
reduce(exec_prefix); reduce(exec_prefix);
reduce(exec_prefix); reduce(exec_prefix);
reduce(exec_prefix); reduce(exec_prefix);
if (!exec_prefix[0]) {
wcscpy(exec_prefix, separator);
}
pathconfig->exec_prefix = _PyMem_RawWcsdup(exec_prefix); if (exec_prefix[0]) {
pathconfig->exec_prefix = exec_prefix;
}
else {
/* empty string: use SEP instead */
PyMem_RawFree(exec_prefix);
/* The exec_prefix is the root directory, but reduce() chopped
off the "/". */
pathconfig->exec_prefix = _PyMem_RawWcsdup(separator);
if (pathconfig->exec_prefix == NULL) {
return _PyStatus_NO_MEMORY();
}
}
} }
else { else {
pathconfig->exec_prefix = _PyMem_RawWcsdup(calculate->exec_prefix_macro); pathconfig->exec_prefix = _PyMem_RawWcsdup(calculate->exec_prefix_macro);
if (pathconfig->exec_prefix == NULL) {
return _PyStatus_NO_MEMORY();
}
} }
if (pathconfig->exec_prefix == NULL) {
return _PyStatus_NO_MEMORY();
}
return _PyStatus_OK(); return _PyStatus_OK();
} }
/* Similar to shutil.which().
If found, write the path into *abs_path_p. */
static PyStatus static PyStatus
calculate_which(const wchar_t *path_env, wchar_t *program_name, calculate_which(const wchar_t *path_env, wchar_t *program_name,
wchar_t *fullpath, size_t fullpath_len, int *found) wchar_t **abs_path_p)
{ {
while (1) { while (1) {
wchar_t *delim = wcschr(path_env, DELIM); wchar_t *delim = wcschr(path_env, DELIM);
wchar_t *abs_path;
if (delim) { if (delim) {
size_t len = delim - path_env; wchar_t *path = substring(path_env, delim - path_env);
if (len >= fullpath_len) { if (path == NULL) {
return PATHLEN_ERR(); return _PyStatus_NO_MEMORY();
} }
wcsncpy(fullpath, path_env, len); abs_path = joinpath2(path, program_name);
fullpath[len] = '\0'; PyMem_RawFree(path);
} }
else { else {
if (safe_wcscpy(fullpath, path_env, abs_path = joinpath2(path_env, program_name);
fullpath_len) < 0) {
return PATHLEN_ERR();
}
} }
PyStatus status = joinpath(fullpath, program_name, fullpath_len); if (abs_path == NULL) {
if (_PyStatus_EXCEPTION(status)) { return _PyStatus_NO_MEMORY();
return status;
} }
if (isxfile(fullpath)) { if (isxfile(abs_path)) {
*found = 1; *abs_path_p = abs_path;
return _PyStatus_OK(); return _PyStatus_OK();
} }
PyMem_RawFree(abs_path);
if (!delim) { if (!delim) {
break; break;
...@@ -850,7 +915,7 @@ calculate_which(const wchar_t *path_env, wchar_t *program_name, ...@@ -850,7 +915,7 @@ calculate_which(const wchar_t *path_env, wchar_t *program_name,
#ifdef __APPLE__ #ifdef __APPLE__
static PyStatus static PyStatus
calculate_program_macos(wchar_t *fullpath, size_t fullpath_len, int *found) calculate_program_macos(wchar_t **abs_path_p)
{ {
char execpath[MAXPATHLEN + 1]; char execpath[MAXPATHLEN + 1];
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
...@@ -877,26 +942,20 @@ calculate_program_macos(wchar_t *fullpath, size_t fullpath_len, int *found) ...@@ -877,26 +942,20 @@ calculate_program_macos(wchar_t *fullpath, size_t fullpath_len, int *found)
} }
size_t len; size_t len;
wchar_t *path = Py_DecodeLocale(execpath, &len); *abs_path_p = Py_DecodeLocale(execpath, &len);
if (path == NULL) { if (*abs_path_p == NULL) {
return DECODE_LOCALE_ERR("executable path", len); return DECODE_LOCALE_ERR("executable path", len);
} }
if (safe_wcscpy(fullpath, path, fullpath_len) < 0) {
PyMem_RawFree(path);
return PATHLEN_ERR();
}
PyMem_RawFree(path);
*found = 1;
return _PyStatus_OK(); return _PyStatus_OK();
} }
#endif /* __APPLE__ */ #endif /* __APPLE__ */
static PyStatus static PyStatus
calculate_program_impl(PyCalculatePath *calculate, _PyPathConfig *pathconfig, calculate_program_impl(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
wchar_t *fullpath, size_t fullpath_len)
{ {
assert(pathconfig->program_full_path == NULL);
PyStatus status; PyStatus status;
/* If there is no slash in the argv0 path, then we have to /* If there is no slash in the argv0 path, then we have to
...@@ -905,39 +964,43 @@ calculate_program_impl(PyCalculatePath *calculate, _PyPathConfig *pathconfig, ...@@ -905,39 +964,43 @@ calculate_program_impl(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
* $PATH isn't exported, you lose. * $PATH isn't exported, you lose.
*/ */
if (wcschr(pathconfig->program_name, SEP)) { if (wcschr(pathconfig->program_name, SEP)) {
if (safe_wcscpy(fullpath, pathconfig->program_name, pathconfig->program_full_path = _PyMem_RawWcsdup(pathconfig->program_name);
fullpath_len) < 0) { if (pathconfig->program_full_path == NULL) {
return PATHLEN_ERR(); return _PyStatus_NO_MEMORY();
} }
return _PyStatus_OK(); return _PyStatus_OK();
} }
#ifdef __APPLE__ #ifdef __APPLE__
int found = 0; wchar_t *abs_path = NULL;
status = calculate_program_macos(fullpath, fullpath_len, &found); status = calculate_program_macos(&abs_path);
if (_PyStatus_EXCEPTION(status)) { if (_PyStatus_EXCEPTION(status)) {
return status; return status;
} }
if (found) { if (abs_path) {
pathconfig->program_full_path = abs_path;
return _PyStatus_OK(); return _PyStatus_OK();
} }
#endif /* __APPLE__ */ #endif /* __APPLE__ */
if (calculate->path_env) { if (calculate->path_env) {
int found = 0; wchar_t *abs_path = NULL;
status = calculate_which(calculate->path_env, pathconfig->program_name, status = calculate_which(calculate->path_env, pathconfig->program_name,
fullpath, fullpath_len, &abs_path);
&found);
if (_PyStatus_EXCEPTION(status)) { if (_PyStatus_EXCEPTION(status)) {
return status; return status;
} }
if (found) { if (abs_path) {
pathconfig->program_full_path = abs_path;
return _PyStatus_OK(); return _PyStatus_OK();
} }
} }
/* In the last resort, use an empty string */ /* In the last resort, use an empty string */
fullpath[0] = '\0'; pathconfig->program_full_path = _PyMem_RawWcsdup(L"");
if (pathconfig->program_full_path == NULL) {
return _PyStatus_NO_MEMORY();
}
return _PyStatus_OK(); return _PyStatus_OK();
} }
...@@ -947,23 +1010,18 @@ static PyStatus ...@@ -947,23 +1010,18 @@ static PyStatus
calculate_program(PyCalculatePath *calculate, _PyPathConfig *pathconfig) calculate_program(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
{ {
PyStatus status; PyStatus status;
wchar_t program_full_path[MAXPATHLEN + 1];
const size_t program_full_path_len = Py_ARRAY_LENGTH(program_full_path);
memset(program_full_path, 0, sizeof(program_full_path));
status = calculate_program_impl(calculate, pathconfig, status = calculate_program_impl(calculate, pathconfig);
program_full_path, program_full_path_len);
if (_PyStatus_EXCEPTION(status)) { if (_PyStatus_EXCEPTION(status)) {
return status; return status;
} }
if (program_full_path[0] != '\0') { if (pathconfig->program_full_path[0] != '\0') {
/* program_full_path is not empty */ /* program_full_path is not empty */
/* Make sure that program_full_path is an absolute path /* Make sure that program_full_path is an absolute path */
(or an empty string) */ if (!_Py_isabs(pathconfig->program_full_path)) {
if (!_Py_isabs(program_full_path)) { status = absolutize(&pathconfig->program_full_path);
status = absolutize(program_full_path, program_full_path_len);
if (_PyStatus_EXCEPTION(status)) { if (_PyStatus_EXCEPTION(status)) {
return status; return status;
} }
...@@ -975,54 +1033,54 @@ calculate_program(PyCalculatePath *calculate, _PyPathConfig *pathconfig) ...@@ -975,54 +1033,54 @@ calculate_program(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
* sys.executable to return the name of a directory under the same * sys.executable to return the name of a directory under the same
* path (bpo-28441). * path (bpo-28441).
*/ */
status = add_exe_suffix(program_full_path, program_full_path_len); status = add_exe_suffix(&pathconfig->program_full_path);
if (_PyStatus_EXCEPTION(status)) { if (_PyStatus_EXCEPTION(status)) {
return status; return status;
} }
#endif #endif
} }
pathconfig->program_full_path = _PyMem_RawWcsdup(program_full_path);
if (pathconfig->program_full_path == NULL) {
return _PyStatus_NO_MEMORY();
}
return _PyStatus_OK(); return _PyStatus_OK();
} }
#if HAVE_READLINK #if HAVE_READLINK
static PyStatus static PyStatus
resolve_symlinks(wchar_t *path, size_t path_len) resolve_symlinks(wchar_t **path_p)
{ {
wchar_t new_path[MAXPATHLEN + 1]; wchar_t new_path[MAXPATHLEN + 1];
const size_t new_path_len = Py_ARRAY_LENGTH(new_path); const size_t new_path_len = Py_ARRAY_LENGTH(new_path);
unsigned int links = 0; unsigned int nlink = 0;
while (1) { while (1) {
int linklen = _Py_wreadlink(path, new_path, new_path_len); int linklen = _Py_wreadlink(*path_p, new_path, new_path_len);
if (linklen == -1) { if (linklen == -1) {
/* not a symbolic link: we are done */
break; break;
} }
if (_Py_isabs(new_path)) { if (_Py_isabs(new_path)) {
/* new_path should never be longer than MAXPATHLEN, PyMem_RawFree(*path_p);
but extra check does not hurt */ *path_p = _PyMem_RawWcsdup(new_path);
if (safe_wcscpy(path, new_path, path_len) < 0) { if (*path_p == NULL) {
return PATHLEN_ERR(); return _PyStatus_NO_MEMORY();
} }
} }
else { else {
/* new_path is relative to path */ /* new_path is relative to path */
reduce(path); reduce(*path_p);
PyStatus status = joinpath(path, new_path, path_len);
if (_PyStatus_EXCEPTION(status)) { wchar_t *abs_path = joinpath2(*path_p, new_path);
return status; if (abs_path == NULL) {
return _PyStatus_NO_MEMORY();
} }
PyMem_RawFree(*path_p);
*path_p = abs_path;
} }
links++; nlink++;
/* 40 is the Linux kernel 4.2 limit */ /* 40 is the Linux kernel 4.2 limit */
if (links >= 40) { if (nlink >= 40) {
return _PyStatus_ERR("maximum number of symbolic links reached"); return _PyStatus_ERR("maximum number of symbolic links reached");
} }
} }
...@@ -1033,9 +1091,7 @@ resolve_symlinks(wchar_t *path, size_t path_len) ...@@ -1033,9 +1091,7 @@ resolve_symlinks(wchar_t *path, size_t path_len)
#ifdef WITH_NEXT_FRAMEWORK #ifdef WITH_NEXT_FRAMEWORK
static PyStatus static PyStatus
calculate_argv0_path_framework(PyCalculatePath *calculate, calculate_argv0_path_framework(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
const wchar_t *program_full_path,
wchar_t *argv0_path, size_t argv0_path_len)
{ {
NSModule pythonModule; NSModule pythonModule;
...@@ -1067,37 +1123,47 @@ calculate_argv0_path_framework(PyCalculatePath *calculate, ...@@ -1067,37 +1123,47 @@ calculate_argv0_path_framework(PyCalculatePath *calculate,
/* Path: reduce(modPath) / lib_python / LANDMARK */ /* Path: reduce(modPath) / lib_python / LANDMARK */
PyStatus status; PyStatus status;
if (safe_wcscpy(argv0_path, wbuf, argv0_path_len) < 0) {
status = PATHLEN_ERR(); wchar_t *parent = _PyMem_RawWcsdup(wbuf);
if (parent == NULL) {
status = _PyStatus_NO_MEMORY();
goto done; goto done;
} }
reduce(argv0_path);
status = joinpath(argv0_path, calculate->lib_python, argv0_path_len); reduce(parent);
if (_PyStatus_EXCEPTION(status)) { wchar_t *lib_python = joinpath2(path, calculate->lib_python);
PyMem_RawFree(parent);
if (lib_python == NULL) {
status = _PyStatus_NO_MEMORY();
goto done; goto done;
} }
int module; int module;
status = ismodule(argv0_path, &module); status = ismodule(lib_python, &module);
PyMem_RawFree(lib_python);
if (_PyStatus_EXCEPTION(status)) { if (_PyStatus_EXCEPTION(status)) {
goto done; goto done;
} }
if (module) { if (!module) {
/* Use the location of the library as argv0_path */
if (safe_wcscpy(argv0_path, wbuf, argv0_path_len) < 0) {
status = PATHLEN_ERR();
goto done;
}
}
else {
/* We are in the build directory so use the name of the /* We are in the build directory so use the name of the
executable - we know that the absolute path is passed */ executable - we know that the absolute path is passed */
if (safe_wcscpy(argv0_path, program_full_path, argv0_path_len) < 0) { PyMem_RawFree(*calculate->argv0_path);
status = PATHLEN_ERR(); calculate->argv0_path = _PyMem_RawWcsdup(pathconfig->program_full_path);
if (calculate->argv0_path == NULL) {
status = _PyStatus_NO_MEMORY();
goto done; goto done;
} }
status = _PyStatus_OK();
goto done;
} }
status = _PyStatus_OK();
/* Use the location of the library as argv0_path */
PyMem_RawFree(*calculate->argv0_path);
calculate->argv0_path = wbuf
return _PyStatus_OK();
done: done:
PyMem_RawFree(wbuf); PyMem_RawFree(wbuf);
...@@ -1108,35 +1174,77 @@ done: ...@@ -1108,35 +1174,77 @@ done:
static PyStatus static PyStatus
calculate_argv0_path(PyCalculatePath *calculate, calculate_argv0_path(PyCalculatePath *calculate,
const wchar_t *program_full_path) _PyPathConfig *pathconfig)
{ {
wchar_t argv0_path[MAXPATHLEN+1]; PyStatus status;
memset(argv0_path, 0, sizeof(argv0_path));
size_t argv0_path_len = Py_ARRAY_LENGTH(argv0_path);
if (safe_wcscpy(argv0_path, program_full_path, argv0_path_len) < 0) { calculate->argv0_path = _PyMem_RawWcsdup(pathconfig->program_full_path);
return PATHLEN_ERR(); if (calculate->argv0_path == NULL) {
return _PyStatus_NO_MEMORY();
} }
#ifdef WITH_NEXT_FRAMEWORK #ifdef WITH_NEXT_FRAMEWORK
PyStatus status; status = calculate_argv0_path_framework(calculate, pathconfig);
status = calculate_argv0_path_framework(calculate, program_full_path,
argv0_path, argv0_path_len);
if (_PyStatus_EXCEPTION(status)) { if (_PyStatus_EXCEPTION(status)) {
return status; return status;
} }
#endif #endif
resolve_symlinks(argv0_path, argv0_path_len); status = resolve_symlinks(&calculate->argv0_path);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
reduce(argv0_path); reduce(calculate->argv0_path);
/* At this point, argv0_path is guaranteed to be less than
MAXPATHLEN bytes long. */
calculate->argv0_path = _PyMem_RawWcsdup(argv0_path); return _PyStatus_OK();
if (calculate->argv0_path == NULL) { }
static PyStatus
calculate_open_pyenv(PyCalculatePath *calculate, FILE **env_file_p)
{
*env_file_p = NULL;
const wchar_t *env_cfg = L"pyvenv.cfg";
/* Filename: <argv0_path> / "pyvenv.cfg" */
wchar_t *filename = joinpath2(calculate->argv0_path, env_cfg);
if (filename == NULL) {
return _PyStatus_NO_MEMORY();
}
*env_file_p = _Py_wfopen(filename, L"r");
PyMem_RawFree(filename);
if (*env_file_p != NULL) {
return _PyStatus_OK();
}
/* fopen() failed: reset errno */
errno = 0;
/* Path: <basename(argv0_path)> / "pyvenv.cfg" */
wchar_t *parent = _PyMem_RawWcsdup(calculate->argv0_path);
if (parent == NULL) {
return _PyStatus_NO_MEMORY();
}
reduce(parent);
filename = joinpath2(parent, env_cfg);
PyMem_RawFree(parent);
if (filename == NULL) {
return _PyStatus_NO_MEMORY(); return _PyStatus_NO_MEMORY();
} }
*env_file_p = _Py_wfopen(filename, L"r");
PyMem_RawFree(filename);
if (*env_file_p == NULL) {
/* fopen() failed: reset errno */
errno = 0;
}
return _PyStatus_OK(); return _PyStatus_OK();
} }
...@@ -1150,53 +1258,28 @@ static PyStatus ...@@ -1150,53 +1258,28 @@ static PyStatus
calculate_read_pyenv(PyCalculatePath *calculate) calculate_read_pyenv(PyCalculatePath *calculate)
{ {
PyStatus status; PyStatus status;
const wchar_t *env_cfg = L"pyvenv.cfg"; FILE *env_file = NULL;
FILE *env_file;
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, calculate->argv0_path, filename_len) < 0) {
return PATHLEN_ERR();
}
status = joinpath(filename, env_cfg, filename_len); status = calculate_open_pyenv(calculate, &env_file);
if (_PyStatus_EXCEPTION(status)) { if (_PyStatus_EXCEPTION(status)) {
return status; return status;
} }
env_file = _Py_wfopen(filename, L"r");
if (env_file == NULL) { if (env_file == NULL) {
errno = 0; /* pyvenv.cfg not found */
return _PyStatus_OK();
/* 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(filename, L"r");
if (env_file == NULL) {
errno = 0;
return _PyStatus_OK();
}
} }
/* Look for a 'home' variable and set argv0_path to it, if found */ /* Look for a 'home' variable and set argv0_path to it, if found */
wchar_t home[MAXPATHLEN+1]; wchar_t *home = NULL;
memset(home, 0, sizeof(home)); status = _Py_FindEnvConfigValue(env_file, L"home", &home);
if (_PyStatus_EXCEPTION(status)) {
fclose(env_file);
return status;
}
if (_Py_FindEnvConfigValue(env_file, L"home", if (home) {
home, Py_ARRAY_LENGTH(home))) {
PyMem_RawFree(calculate->argv0_path); PyMem_RawFree(calculate->argv0_path);
calculate->argv0_path = _PyMem_RawWcsdup(home); calculate->argv0_path = home;
if (calculate->argv0_path == NULL) {
fclose(env_file);
return _PyStatus_NO_MEMORY();
}
} }
fclose(env_file); fclose(env_file);
return _PyStatus_OK(); return _PyStatus_OK();
...@@ -1206,39 +1289,34 @@ calculate_read_pyenv(PyCalculatePath *calculate) ...@@ -1206,39 +1289,34 @@ calculate_read_pyenv(PyCalculatePath *calculate)
static PyStatus static PyStatus
calculate_zip_path(PyCalculatePath *calculate) calculate_zip_path(PyCalculatePath *calculate)
{ {
PyStatus status; const wchar_t *lib_python = L"lib/python00.zip";
wchar_t zip_path[MAXPATHLEN+1]; /* ".../lib/pythonXY.zip" */
memset(zip_path, 0, sizeof(zip_path));
size_t zip_path_len = Py_ARRAY_LENGTH(zip_path);
if (calculate->prefix_found > 0) { if (calculate->prefix_found > 0) {
/* Use the reduced prefix returned by Py_GetPrefix() */ /* Use the reduced prefix returned by Py_GetPrefix()
if (safe_wcscpy(zip_path, calculate->prefix, zip_path_len) < 0) {
return PATHLEN_ERR(); Path: <basename(basename(prefix))> / <lib_python> */
wchar_t *parent = _PyMem_RawWcsdup(calculate->prefix);
if (parent == NULL) {
return _PyStatus_NO_MEMORY();
} }
reduce(zip_path); reduce(parent);
reduce(zip_path); reduce(parent);
calculate->zip_path = joinpath2(parent, lib_python);
PyMem_RawFree(parent);
} }
else { else {
if (safe_wcscpy(zip_path, calculate->prefix_macro, zip_path_len) < 0) { calculate->zip_path = joinpath2(calculate->prefix_macro, lib_python);
return PATHLEN_ERR();
}
}
status = joinpath(zip_path, L"lib/python00.zip", zip_path_len);
if (_PyStatus_EXCEPTION(status)) {
return status;
} }
/* Replace "00" with version */
size_t bufsz = wcslen(zip_path);
zip_path[bufsz - 6] = VERSION[0];
zip_path[bufsz - 5] = VERSION[2];
calculate->zip_path = _PyMem_RawWcsdup(zip_path);
if (calculate->zip_path == NULL) { if (calculate->zip_path == NULL) {
return _PyStatus_NO_MEMORY(); return _PyStatus_NO_MEMORY();
} }
/* Replace "00" with version */
size_t len = wcslen(calculate->zip_path);
calculate->zip_path[len - 6] = VERSION[0];
calculate->zip_path[len - 5] = VERSION[2];
return _PyStatus_OK(); return _PyStatus_OK();
} }
...@@ -1344,22 +1422,27 @@ calculate_init(PyCalculatePath *calculate, const PyConfig *config) ...@@ -1344,22 +1422,27 @@ calculate_init(PyCalculatePath *calculate, const PyConfig *config)
} }
} }
/* Decode macros */
calculate->pythonpath_macro = Py_DecodeLocale(PYTHONPATH, &len); calculate->pythonpath_macro = Py_DecodeLocale(PYTHONPATH, &len);
if (!calculate->pythonpath_macro) { if (!calculate->pythonpath_macro) {
return DECODE_LOCALE_ERR("PYTHONPATH define", len); return DECODE_LOCALE_ERR("PYTHONPATH macro", len);
} }
calculate->prefix_macro = Py_DecodeLocale(PREFIX, &len); calculate->prefix_macro = Py_DecodeLocale(PREFIX, &len);
if (!calculate->prefix_macro) { if (!calculate->prefix_macro) {
return DECODE_LOCALE_ERR("PREFIX define", len); return DECODE_LOCALE_ERR("PREFIX macro", len);
} }
calculate->exec_prefix_macro = Py_DecodeLocale(EXEC_PREFIX, &len); calculate->exec_prefix_macro = Py_DecodeLocale(EXEC_PREFIX, &len);
if (!calculate->exec_prefix_macro) { if (!calculate->exec_prefix_macro) {
return DECODE_LOCALE_ERR("EXEC_PREFIX define", len); return DECODE_LOCALE_ERR("EXEC_PREFIX macro", len);
} }
calculate->vpath_macro = Py_DecodeLocale(VPATH, &len);
if (!calculate->vpath_macro) {
return DECODE_LOCALE_ERR("VPATH macro", len);
}
calculate->lib_python = Py_DecodeLocale("lib/python" VERSION, &len); calculate->lib_python = Py_DecodeLocale("lib/python" VERSION, &len);
if (!calculate->lib_python) { if (!calculate->lib_python) {
return DECODE_LOCALE_ERR("EXEC_PREFIX define", len); return DECODE_LOCALE_ERR("EXEC_PREFIX macro", len);
} }
calculate->warnings = config->pathconfig_warnings; calculate->warnings = config->pathconfig_warnings;
...@@ -1375,6 +1458,7 @@ calculate_free(PyCalculatePath *calculate) ...@@ -1375,6 +1458,7 @@ calculate_free(PyCalculatePath *calculate)
PyMem_RawFree(calculate->pythonpath_macro); PyMem_RawFree(calculate->pythonpath_macro);
PyMem_RawFree(calculate->prefix_macro); PyMem_RawFree(calculate->prefix_macro);
PyMem_RawFree(calculate->exec_prefix_macro); PyMem_RawFree(calculate->exec_prefix_macro);
PyMem_RawFree(calculate->vpath_macro);
PyMem_RawFree(calculate->lib_python); PyMem_RawFree(calculate->lib_python);
PyMem_RawFree(calculate->path_env); PyMem_RawFree(calculate->path_env);
PyMem_RawFree(calculate->zip_path); PyMem_RawFree(calculate->zip_path);
...@@ -1396,7 +1480,7 @@ calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig) ...@@ -1396,7 +1480,7 @@ calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
} }
} }
status = calculate_argv0_path(calculate, pathconfig->program_full_path); status = calculate_argv0_path(calculate, pathconfig);
if (_PyStatus_EXCEPTION(status)) { if (_PyStatus_EXCEPTION(status)) {
return status; return status;
} }
...@@ -1501,6 +1585,10 @@ _PyPathConfig_Calculate(_PyPathConfig *pathconfig, const PyConfig *config) ...@@ -1501,6 +1585,10 @@ _PyPathConfig_Calculate(_PyPathConfig *pathconfig, const PyConfig *config)
goto done; goto done;
} }
/* program_full_path must an either an empty string or an absolute path */
assert(wcslen(pathconfig->program_full_path) == 0
|| _Py_isabs(pathconfig->program_full_path));
status = _PyStatus_OK(); status = _PyStatus_OK();
done: done:
......
...@@ -752,7 +752,7 @@ calculate_pth_file(PyCalculatePath *calculate, _PyPathConfig *pathconfig, ...@@ -752,7 +752,7 @@ calculate_pth_file(PyCalculatePath *calculate, _PyPathConfig *pathconfig,
executable's directory and then in the parent directory. executable's directory and then in the parent directory.
If found, open it for use when searching for prefixes. If found, open it for use when searching for prefixes.
*/ */
static void static PyStatus
calculate_pyvenv_file(PyCalculatePath *calculate, calculate_pyvenv_file(PyCalculatePath *calculate,
wchar_t *argv0_path, size_t argv0_path_len) wchar_t *argv0_path, size_t argv0_path_len)
{ {
...@@ -775,17 +775,23 @@ calculate_pyvenv_file(PyCalculatePath *calculate, ...@@ -775,17 +775,23 @@ calculate_pyvenv_file(PyCalculatePath *calculate,
env_file = _Py_wfopen(filename, L"r"); env_file = _Py_wfopen(filename, L"r");
if (env_file == NULL) { if (env_file == NULL) {
errno = 0; errno = 0;
return; return _PyStatus_OK();
} }
} }
/* Look for a 'home' variable and set argv0_path to it, if found */ /* Look for a 'home' variable and set argv0_path to it, if found */
wchar_t home[MAXPATHLEN+1]; wchar_t *home = NULL;
if (_Py_FindEnvConfigValue(env_file, L"home", PyStatus status = _Py_FindEnvConfigValue(env_file, L"home", &home);
home, Py_ARRAY_LENGTH(home))) { if (_PyStatus_EXCEPTION(status)) {
fclose(env_file);
return status;
}
if (home) {
wcscpy_s(argv0_path, argv0_path_len, home); wcscpy_s(argv0_path, argv0_path_len, home);
PyMem_RawFree(home);
} }
fclose(env_file); fclose(env_file);
return _PyStatus_OK();
} }
...@@ -1022,7 +1028,11 @@ calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig) ...@@ -1022,7 +1028,11 @@ calculate_path(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
goto done; goto done;
} }
calculate_pyvenv_file(calculate, argv0_path, Py_ARRAY_LENGTH(argv0_path)); status = calculate_pyvenv_file(calculate,
argv0_path, Py_ARRAY_LENGTH(argv0_path));
if (_PyStatus_EXCEPTION(status)) {
return status;
}
/* Calculate zip archive path from DLL or exe path */ /* Calculate zip archive path from DLL or exe path */
wchar_t zip_path[MAXPATHLEN+1]; wchar_t zip_path[MAXPATHLEN+1];
......
...@@ -777,12 +777,17 @@ _PyPathConfig_ComputeSysPath0(const PyWideStringList *argv, PyObject **path0_p) ...@@ -777,12 +777,17 @@ _PyPathConfig_ComputeSysPath0(const PyWideStringList *argv, PyObject **path0_p)
#endif #endif
/* Search for a prefix value in an environment file (pyvenv.cfg). /* Search for a prefix value in an environment file (pyvenv.cfg).
If found, copy it into the provided buffer. */
int - If found, copy it into *value_p: string which must be freed by
PyMem_RawFree().
- If not found, *value_p is set to NULL.
*/
PyStatus
_Py_FindEnvConfigValue(FILE *env_file, const wchar_t *key, _Py_FindEnvConfigValue(FILE *env_file, const wchar_t *key,
wchar_t *value, size_t value_size) wchar_t **value_p)
{ {
int result = 0; /* meaning not found */ *value_p = NULL;
char buffer[MAXPATHLEN * 2 + 1]; /* allow extra for key, '=', etc. */ char buffer[MAXPATHLEN * 2 + 1]; /* allow extra for key, '=', etc. */
buffer[Py_ARRAY_LENGTH(buffer)-1] = '\0'; buffer[Py_ARRAY_LENGTH(buffer)-1] = '\0';
...@@ -812,18 +817,24 @@ _Py_FindEnvConfigValue(FILE *env_file, const wchar_t *key, ...@@ -812,18 +817,24 @@ _Py_FindEnvConfigValue(FILE *env_file, const wchar_t *key,
if ((tok != NULL) && !wcscmp(tok, L"=")) { if ((tok != NULL) && !wcscmp(tok, L"=")) {
tok = WCSTOK(NULL, L"\r\n", &state); tok = WCSTOK(NULL, L"\r\n", &state);
if (tok != NULL) { if (tok != NULL) {
wcsncpy(value, tok, value_size - 1); *value_p = _PyMem_RawWcsdup(tok);
value[value_size - 1] = L'\0';
result = 1;
PyMem_RawFree(tmpbuffer); PyMem_RawFree(tmpbuffer);
break;
if (*value_p == NULL) {
return _PyStatus_NO_MEMORY();
}
/* found */
return _PyStatus_OK();
} }
} }
} }
PyMem_RawFree(tmpbuffer); PyMem_RawFree(tmpbuffer);
} }
} }
return result;
/* not found */
return _PyStatus_OK();
} }
#ifdef __cplusplus #ifdef __cplusplus
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment