bpo-32030: Add _PyPathConfig_Init() (#4551)

* Add _PyPathConfig_Init() and _PyPathConfig_Fini()
* Remove _Py_GetPathWithConfig()
* _PyPathConfig_Init() returns _PyInitError to allow to handle errors
  properly
* Add pathconfig_clear()
* Windows calculate_path_impl(): replace Py_FatalError() with
  _PyInitError
* Py_FinalizeEx() now calls _PyPathConfig_Fini() to release memory
* Fix _Py_InitializeMainInterpreter() regression: don't initialize
  path config if _disable_importlib is false
* PyPathConfig now uses dynamically allocated memory
This commit is contained in:
Victor Stinner 2017-11-25 03:17:57 +01:00 committed by GitHub
parent 706cb3162e
commit 9316ee4da2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 478 additions and 309 deletions

View file

@ -103,8 +103,9 @@ PyAPI_FUNC(wchar_t *) Py_GetPrefix(void);
PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void); PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void);
PyAPI_FUNC(wchar_t *) Py_GetPath(void); PyAPI_FUNC(wchar_t *) Py_GetPath(void);
#ifdef Py_BUILD_CORE #ifdef Py_BUILD_CORE
PyAPI_FUNC(wchar_t *) _Py_GetPathWithConfig( PyAPI_FUNC(_PyInitError) _PyPathConfig_Init(
const _PyMainInterpreterConfig *config); const _PyMainInterpreterConfig *main_config);
PyAPI_FUNC(void) _PyPathConfig_Fini(void);
#endif #endif
PyAPI_FUNC(void) Py_SetPath(const wchar_t *); PyAPI_FUNC(void) Py_SetPath(const wchar_t *);
#ifdef MS_WINDOWS #ifdef MS_WINDOWS

View file

@ -109,10 +109,16 @@ extern "C" {
#define LANDMARK L"os.py" #define LANDMARK L"os.py"
#endif #endif
#define DECODE_LOCALE_ERR(NAME, LEN) \
((LEN) == (size_t)-2) \
? _Py_INIT_USER_ERR("cannot decode " #NAME) \
: _Py_INIT_NO_MEMORY()
typedef struct { typedef struct {
wchar_t prefix[MAXPATHLEN+1]; wchar_t *prefix;
wchar_t exec_prefix[MAXPATHLEN+1]; wchar_t *exec_prefix;
wchar_t program_name[MAXPATHLEN+1]; wchar_t *program_name;
wchar_t *module_search_path; wchar_t *module_search_path;
} PyPathConfig; } PyPathConfig;
@ -361,63 +367,63 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value)
bytes long. bytes long.
*/ */
static int static int
search_for_prefix(PyCalculatePath *calculate, PyPathConfig *config) search_for_prefix(PyCalculatePath *calculate, wchar_t *prefix)
{ {
size_t n; size_t n;
wchar_t *vpath; wchar_t *vpath;
/* If PYTHONHOME is set, we believe it unconditionally */ /* If PYTHONHOME is set, we believe it unconditionally */
if (calculate->home) { if (calculate->home) {
wcsncpy(config->prefix, calculate->home, MAXPATHLEN); wcsncpy(prefix, calculate->home, MAXPATHLEN);
config->prefix[MAXPATHLEN] = L'\0'; prefix[MAXPATHLEN] = L'\0';
wchar_t *delim = wcschr(config->prefix, DELIM); wchar_t *delim = wcschr(prefix, DELIM);
if (delim) { if (delim) {
*delim = L'\0'; *delim = L'\0';
} }
joinpath(config->prefix, calculate->lib_python); joinpath(prefix, calculate->lib_python);
joinpath(config->prefix, LANDMARK); joinpath(prefix, LANDMARK);
return 1; return 1;
} }
/* Check to see if argv[0] is in the build directory */ /* Check to see if argv[0] is in the build directory */
wcsncpy(config->prefix, calculate->argv0_path, MAXPATHLEN); wcsncpy(prefix, calculate->argv0_path, MAXPATHLEN);
config->prefix[MAXPATHLEN] = L'\0'; prefix[MAXPATHLEN] = L'\0';
joinpath(config->prefix, L"Modules/Setup"); joinpath(prefix, L"Modules/Setup");
if (isfile(config->prefix)) { if (isfile(prefix)) {
/* Check VPATH to see if argv0_path is in the build directory. */ /* Check VPATH to see if argv0_path is in the build directory. */
vpath = Py_DecodeLocale(VPATH, NULL); vpath = Py_DecodeLocale(VPATH, NULL);
if (vpath != NULL) { if (vpath != NULL) {
wcsncpy(config->prefix, calculate->argv0_path, MAXPATHLEN); wcsncpy(prefix, calculate->argv0_path, MAXPATHLEN);
config->prefix[MAXPATHLEN] = L'\0'; prefix[MAXPATHLEN] = L'\0';
joinpath(config->prefix, vpath); joinpath(prefix, vpath);
PyMem_RawFree(vpath); PyMem_RawFree(vpath);
joinpath(config->prefix, L"Lib"); joinpath(prefix, L"Lib");
joinpath(config->prefix, LANDMARK); joinpath(prefix, LANDMARK);
if (ismodule(config->prefix)) { if (ismodule(prefix)) {
return -1; return -1;
} }
} }
} }
/* Search from argv0_path, until root is found */ /* Search from argv0_path, until root is found */
copy_absolute(config->prefix, calculate->argv0_path, MAXPATHLEN+1); copy_absolute(prefix, calculate->argv0_path, MAXPATHLEN+1);
do { do {
n = wcslen(config->prefix); n = wcslen(prefix);
joinpath(config->prefix, calculate->lib_python); joinpath(prefix, calculate->lib_python);
joinpath(config->prefix, LANDMARK); joinpath(prefix, LANDMARK);
if (ismodule(config->prefix)) { if (ismodule(prefix)) {
return 1; return 1;
} }
config->prefix[n] = L'\0'; prefix[n] = L'\0';
reduce(config->prefix); reduce(prefix);
} while (config->prefix[0]); } while (prefix[0]);
/* Look at configure's PREFIX */ /* Look at configure's PREFIX */
wcsncpy(config->prefix, calculate->prefix, MAXPATHLEN); wcsncpy(prefix, calculate->prefix, MAXPATHLEN);
config->prefix[MAXPATHLEN] = L'\0'; prefix[MAXPATHLEN] = L'\0';
joinpath(config->prefix, calculate->lib_python); joinpath(prefix, calculate->lib_python);
joinpath(config->prefix, LANDMARK); joinpath(prefix, LANDMARK);
if (ismodule(config->prefix)) { if (ismodule(prefix)) {
return 1; return 1;
} }
@ -427,25 +433,25 @@ search_for_prefix(PyCalculatePath *calculate, PyPathConfig *config)
static void static void
calculate_prefix(PyCalculatePath *calculate, PyPathConfig *config) calculate_prefix(PyCalculatePath *calculate, wchar_t *prefix)
{ {
calculate->prefix_found = search_for_prefix(calculate, config); calculate->prefix_found = search_for_prefix(calculate, prefix);
if (!calculate->prefix_found) { if (!calculate->prefix_found) {
if (!Py_FrozenFlag) { if (!Py_FrozenFlag) {
fprintf(stderr, fprintf(stderr,
"Could not find platform independent libraries <prefix>\n"); "Could not find platform independent libraries <prefix>\n");
} }
wcsncpy(config->prefix, calculate->prefix, MAXPATHLEN); wcsncpy(prefix, calculate->prefix, MAXPATHLEN);
joinpath(config->prefix, calculate->lib_python); joinpath(prefix, calculate->lib_python);
} }
else { else {
reduce(config->prefix); reduce(prefix);
} }
} }
static void static void
calculate_reduce_prefix(PyCalculatePath *calculate, PyPathConfig *config) calculate_reduce_prefix(PyCalculatePath *calculate, wchar_t *prefix)
{ {
/* Reduce prefix and exec_prefix to their essence, /* Reduce prefix and exec_prefix to their essence,
* e.g. /usr/local/lib/python1.5 is reduced to /usr/local. * e.g. /usr/local/lib/python1.5 is reduced to /usr/local.
@ -453,16 +459,16 @@ calculate_reduce_prefix(PyCalculatePath *calculate, PyPathConfig *config)
* return the compiled-in defaults instead. * return the compiled-in defaults instead.
*/ */
if (calculate->prefix_found > 0) { if (calculate->prefix_found > 0) {
reduce(config->prefix); reduce(prefix);
reduce(config->prefix); reduce(prefix);
/* The prefix is the root directory, but reduce() chopped /* The prefix is the root directory, but reduce() chopped
* off the "/". */ * off the "/". */
if (!config->prefix[0]) { if (!prefix[0]) {
wcscpy(config->prefix, separator); wcscpy(prefix, separator);
} }
} }
else { else {
wcsncpy(config->prefix, calculate->prefix, MAXPATHLEN); wcsncpy(prefix, calculate->prefix, MAXPATHLEN);
} }
} }
@ -471,7 +477,7 @@ calculate_reduce_prefix(PyCalculatePath *calculate, PyPathConfig *config)
MAXPATHLEN bytes long. MAXPATHLEN bytes long.
*/ */
static int static int
search_for_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config) search_for_exec_prefix(PyCalculatePath *calculate, wchar_t *exec_prefix)
{ {
size_t n; size_t n;
@ -479,25 +485,25 @@ search_for_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
if (calculate->home) { if (calculate->home) {
wchar_t *delim = wcschr(calculate->home, DELIM); wchar_t *delim = wcschr(calculate->home, DELIM);
if (delim) { if (delim) {
wcsncpy(config->exec_prefix, delim+1, MAXPATHLEN); wcsncpy(exec_prefix, delim+1, MAXPATHLEN);
} }
else { else {
wcsncpy(config->exec_prefix, calculate->home, MAXPATHLEN); wcsncpy(exec_prefix, calculate->home, MAXPATHLEN);
} }
config->exec_prefix[MAXPATHLEN] = L'\0'; exec_prefix[MAXPATHLEN] = L'\0';
joinpath(config->exec_prefix, calculate->lib_python); joinpath(exec_prefix, calculate->lib_python);
joinpath(config->exec_prefix, L"lib-dynload"); joinpath(exec_prefix, L"lib-dynload");
return 1; return 1;
} }
/* 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. */
wcsncpy(config->exec_prefix, calculate->argv0_path, MAXPATHLEN); wcsncpy(exec_prefix, calculate->argv0_path, MAXPATHLEN);
config->exec_prefix[MAXPATHLEN] = L'\0'; exec_prefix[MAXPATHLEN] = L'\0';
joinpath(config->exec_prefix, L"pybuilddir.txt"); joinpath(exec_prefix, L"pybuilddir.txt");
if (isfile(config->exec_prefix)) { if (isfile(exec_prefix)) {
FILE *f = _Py_wfopen(config->exec_prefix, L"rb"); FILE *f = _Py_wfopen(exec_prefix, L"rb");
if (f == NULL) { if (f == NULL) {
errno = 0; errno = 0;
} }
@ -516,9 +522,9 @@ search_for_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
Py_DECREF(decoded); Py_DECREF(decoded);
if (k >= 0) { if (k >= 0) {
rel_builddir_path[k] = L'\0'; rel_builddir_path[k] = L'\0';
wcsncpy(config->exec_prefix, calculate->argv0_path, MAXPATHLEN); wcsncpy(exec_prefix, calculate->argv0_path, MAXPATHLEN);
config->exec_prefix[MAXPATHLEN] = L'\0'; exec_prefix[MAXPATHLEN] = L'\0';
joinpath(config->exec_prefix, rel_builddir_path); joinpath(exec_prefix, rel_builddir_path);
return -1; return -1;
} }
} }
@ -526,24 +532,24 @@ search_for_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
} }
/* Search from argv0_path, until root is found */ /* Search from argv0_path, until root is found */
copy_absolute(config->exec_prefix, calculate->argv0_path, MAXPATHLEN+1); copy_absolute(exec_prefix, calculate->argv0_path, MAXPATHLEN+1);
do { do {
n = wcslen(config->exec_prefix); n = wcslen(exec_prefix);
joinpath(config->exec_prefix, calculate->lib_python); joinpath(exec_prefix, calculate->lib_python);
joinpath(config->exec_prefix, L"lib-dynload"); joinpath(exec_prefix, L"lib-dynload");
if (isdir(config->exec_prefix)) { if (isdir(exec_prefix)) {
return 1; return 1;
} }
config->exec_prefix[n] = L'\0'; exec_prefix[n] = L'\0';
reduce(config->exec_prefix); reduce(exec_prefix);
} while (config->exec_prefix[0]); } while (exec_prefix[0]);
/* Look at configure's EXEC_PREFIX */ /* Look at configure's EXEC_PREFIX */
wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN); wcsncpy(exec_prefix, calculate->exec_prefix, MAXPATHLEN);
config->exec_prefix[MAXPATHLEN] = L'\0'; exec_prefix[MAXPATHLEN] = L'\0';
joinpath(config->exec_prefix, calculate->lib_python); joinpath(exec_prefix, calculate->lib_python);
joinpath(config->exec_prefix, L"lib-dynload"); joinpath(exec_prefix, L"lib-dynload");
if (isdir(config->exec_prefix)) { if (isdir(exec_prefix)) {
return 1; return 1;
} }
@ -553,41 +559,44 @@ search_for_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config)
static void static void
calculate_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config) calculate_exec_prefix(PyCalculatePath *calculate, wchar_t *exec_prefix)
{ {
calculate->exec_prefix_found = search_for_exec_prefix(calculate, config); calculate->exec_prefix_found = search_for_exec_prefix(calculate, exec_prefix);
if (!calculate->exec_prefix_found) { if (!calculate->exec_prefix_found) {
if (!Py_FrozenFlag) { if (!Py_FrozenFlag) {
fprintf(stderr, fprintf(stderr,
"Could not find platform dependent libraries <exec_prefix>\n"); "Could not find platform dependent libraries <exec_prefix>\n");
} }
wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN); wcsncpy(exec_prefix, calculate->exec_prefix, MAXPATHLEN);
joinpath(config->exec_prefix, L"lib/lib-dynload"); joinpath(exec_prefix, L"lib/lib-dynload");
} }
/* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */ /* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */
} }
static void static void
calculate_reduce_exec_prefix(PyCalculatePath *calculate, PyPathConfig *config) calculate_reduce_exec_prefix(PyCalculatePath *calculate, wchar_t *exec_prefix)
{ {
if (calculate->exec_prefix_found > 0) { if (calculate->exec_prefix_found > 0) {
reduce(config->exec_prefix); reduce(exec_prefix);
reduce(config->exec_prefix); reduce(exec_prefix);
reduce(config->exec_prefix); reduce(exec_prefix);
if (!config->exec_prefix[0]) { if (!exec_prefix[0]) {
wcscpy(config->exec_prefix, separator); wcscpy(exec_prefix, separator);
} }
} }
else { else {
wcsncpy(config->exec_prefix, calculate->exec_prefix, MAXPATHLEN); wcsncpy(exec_prefix, calculate->exec_prefix, MAXPATHLEN);
} }
} }
static void static _PyInitError
calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config) calculate_program_name(PyCalculatePath *calculate, PyPathConfig *config)
{ {
wchar_t program_name[MAXPATHLEN+1];
memset(program_name, 0, sizeof(program_name));
#ifdef __APPLE__ #ifdef __APPLE__
#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
uint32_t nsexeclength = MAXPATHLEN; uint32_t nsexeclength = MAXPATHLEN;
@ -603,7 +612,7 @@ calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config)
* $PATH isn't exported, you lose. * $PATH isn't exported, you lose.
*/ */
if (wcschr(calculate->program_name, SEP)) { if (wcschr(calculate->program_name, SEP)) {
wcsncpy(config->program_name, calculate->program_name, MAXPATHLEN); wcsncpy(program_name, calculate->program_name, MAXPATHLEN);
} }
#ifdef __APPLE__ #ifdef __APPLE__
/* On Mac OS X, if a script uses an interpreter of the form /* On Mac OS X, if a script uses an interpreter of the form
@ -619,10 +628,10 @@ calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config)
else if(0 == _NSGetExecutablePath(execpath, &nsexeclength) && else if(0 == _NSGetExecutablePath(execpath, &nsexeclength) &&
execpath[0] == SEP) execpath[0] == SEP)
{ {
size_t r = mbstowcs(config->program_name, execpath, MAXPATHLEN+1); size_t r = mbstowcs(program_name, execpath, MAXPATHLEN+1);
if (r == (size_t)-1 || r > MAXPATHLEN) { if (r == (size_t)-1 || r > MAXPATHLEN) {
/* Could not convert execpath, or it's too long. */ /* Could not convert execpath, or it's too long. */
config->program_name[0] = '\0'; program_name[0] = '\0';
} }
} }
#endif /* __APPLE__ */ #endif /* __APPLE__ */
@ -636,38 +645,44 @@ calculate_progpath(PyCalculatePath *calculate, PyPathConfig *config)
if (len > MAXPATHLEN) { if (len > MAXPATHLEN) {
len = MAXPATHLEN; len = MAXPATHLEN;
} }
wcsncpy(config->program_name, path, len); wcsncpy(program_name, path, len);
*(config->program_name + len) = '\0'; program_name[len] = '\0';
} }
else { else {
wcsncpy(config->program_name, path, MAXPATHLEN); wcsncpy(program_name, path, MAXPATHLEN);
} }
joinpath(config->program_name, calculate->program_name); joinpath(program_name, calculate->program_name);
if (isxfile(config->program_name)) { if (isxfile(program_name)) {
break; break;
} }
if (!delim) { if (!delim) {
config->program_name[0] = L'\0'; program_name[0] = L'\0';
break; break;
} }
path = delim + 1; path = delim + 1;
} }
} }
else { else {
config->program_name[0] = '\0'; program_name[0] = '\0';
} }
if (config->program_name[0] != SEP && config->program_name[0] != '\0') { if (program_name[0] != SEP && program_name[0] != '\0') {
absolutize(config->program_name); absolutize(program_name);
} }
config->program_name = _PyMem_RawWcsdup(program_name);
if (config->program_name == NULL) {
return _Py_INIT_NO_MEMORY();
}
return _Py_INIT_OK();
} }
static void static _PyInitError
calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config) calculate_argv0_path(PyCalculatePath *calculate, const wchar_t *program_name)
{ {
wcsncpy(calculate->argv0_path, config->program_name, MAXPATHLEN); wcsncpy(calculate->argv0_path, program_name, MAXPATHLEN);
calculate->argv0_path[MAXPATHLEN] = '\0'; calculate->argv0_path[MAXPATHLEN] = '\0';
#ifdef WITH_NEXT_FRAMEWORK #ifdef WITH_NEXT_FRAMEWORK
@ -690,9 +705,10 @@ calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config)
** be running the interpreter in the build directory, so we use the ** be running the interpreter in the build directory, so we use the
** build-directory-specific logic to find Lib and such. ** build-directory-specific logic to find Lib and such.
*/ */
wchar_t* wbuf = Py_DecodeLocale(modPath, NULL); size_t len;
wchar_t* wbuf = Py_DecodeLocale(modPath, &len);
if (wbuf == NULL) { if (wbuf == NULL) {
Py_FatalError("Cannot decode framework location"); return DECODE_LOCALE_ERR("framework location", len);
} }
wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN); wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN);
@ -702,7 +718,7 @@ calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config)
if (!ismodule(calculate->argv0_path)) { if (!ismodule(calculate->argv0_path)) {
/* 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 */
wcsncpy(calculate->argv0_path, config->program_name, MAXPATHLEN); wcsncpy(calculate->argv0_path, program_name, MAXPATHLEN);
} }
else { else {
/* Use the location of the library as the program_name */ /* Use the location of the library as the program_name */
@ -714,7 +730,7 @@ calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config)
#if HAVE_READLINK #if HAVE_READLINK
wchar_t tmpbuffer[MAXPATHLEN+1]; wchar_t tmpbuffer[MAXPATHLEN+1];
int linklen = _Py_wreadlink(config->program_name, tmpbuffer, MAXPATHLEN); int linklen = _Py_wreadlink(program_name, tmpbuffer, MAXPATHLEN);
while (linklen != -1) { while (linklen != -1) {
if (tmpbuffer[0] == SEP) { if (tmpbuffer[0] == SEP) {
/* tmpbuffer should never be longer than MAXPATHLEN, /* tmpbuffer should never be longer than MAXPATHLEN,
@ -733,6 +749,7 @@ calculate_argv0_path(PyCalculatePath *calculate, PyPathConfig *config)
reduce(calculate->argv0_path); reduce(calculate->argv0_path);
/* At this point, argv0_path is guaranteed to be less than /* At this point, argv0_path is guaranteed to be less than
MAXPATHLEN bytes long. */ MAXPATHLEN bytes long. */
return _Py_INIT_OK();
} }
@ -777,9 +794,9 @@ calculate_read_pyenv(PyCalculatePath *calculate)
static void static void
calculate_zip_path(PyCalculatePath *calculate, PyPathConfig *config) calculate_zip_path(PyCalculatePath *calculate, const wchar_t *prefix)
{ {
wcsncpy(calculate->zip_path, config->prefix, MAXPATHLEN); wcsncpy(calculate->zip_path, prefix, MAXPATHLEN);
calculate->zip_path[MAXPATHLEN] = L'\0'; calculate->zip_path[MAXPATHLEN] = L'\0';
if (calculate->prefix_found > 0) { if (calculate->prefix_found > 0) {
@ -799,8 +816,10 @@ calculate_zip_path(PyCalculatePath *calculate, PyPathConfig *config)
} }
static wchar_t * static _PyInitError
calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config) calculate_module_search_path(PyCalculatePath *calculate,
const wchar_t *prefix, const wchar_t *exec_prefix,
PyPathConfig *config)
{ {
/* Calculate size of return buffer */ /* Calculate size of return buffer */
size_t bufsz = 0; size_t bufsz = 0;
@ -809,7 +828,7 @@ calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config)
} }
wchar_t *defpath = calculate->pythonpath; wchar_t *defpath = calculate->pythonpath;
size_t prefixsz = wcslen(config->prefix) + 1; size_t prefixsz = wcslen(prefix) + 1;
while (1) { while (1) {
wchar_t *delim = wcschr(defpath, DELIM); wchar_t *delim = wcschr(defpath, DELIM);
@ -829,13 +848,12 @@ calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config)
} }
bufsz += wcslen(calculate->zip_path) + 1; bufsz += wcslen(calculate->zip_path) + 1;
bufsz += wcslen(config->exec_prefix) + 1; bufsz += wcslen(exec_prefix) + 1;
/* Allocate the buffer */ /* Allocate the buffer */
wchar_t *buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t)); wchar_t *buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t));
if (buf == NULL) { if (buf == NULL) {
Py_FatalError( return _Py_INIT_NO_MEMORY();
"Not enough memory for dynamic PYTHONPATH");
} }
buf[0] = '\0'; buf[0] = '\0';
@ -857,8 +875,8 @@ calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config)
wchar_t *delim = wcschr(defpath, DELIM); wchar_t *delim = wcschr(defpath, DELIM);
if (defpath[0] != SEP) { if (defpath[0] != SEP) {
wcscat(buf, config->prefix); wcscat(buf, prefix);
if (prefixsz >= 2 && config->prefix[prefixsz - 2] != SEP && if (prefixsz >= 2 && prefix[prefixsz - 2] != SEP &&
defpath[0] != (delim ? DELIM : L'\0')) defpath[0] != (delim ? DELIM : L'\0'))
{ {
/* not empty */ /* not empty */
@ -870,7 +888,7 @@ calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config)
size_t len = delim - defpath + 1; size_t len = delim - defpath + 1;
size_t end = wcslen(buf) + len; size_t end = wcslen(buf) + len;
wcsncat(buf, defpath, len); wcsncat(buf, defpath, len);
*(buf + end) = '\0'; buf[end] = '\0';
} }
else { else {
wcscat(buf, defpath); wcscat(buf, defpath);
@ -881,18 +899,13 @@ calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config)
wcscat(buf, delimiter); wcscat(buf, delimiter);
/* Finally, on goes the directory for dynamic-load modules */ /* Finally, on goes the directory for dynamic-load modules */
wcscat(buf, config->exec_prefix); wcscat(buf, exec_prefix);
return buf; config->module_search_path = buf;
return _Py_INIT_OK();
} }
#define DECODE_LOCALE_ERR(NAME, LEN) \
((LEN) == (size_t)-2) \
? _Py_INIT_USER_ERR("failed to decode " #NAME) \
: _Py_INIT_NO_MEMORY()
static _PyInitError static _PyInitError
calculate_init(PyCalculatePath *calculate, calculate_init(PyCalculatePath *calculate,
const _PyMainInterpreterConfig *main_config) const _PyMainInterpreterConfig *main_config)
@ -941,15 +954,30 @@ calculate_free(PyCalculatePath *calculate)
} }
static void static _PyInitError
calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config) calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config)
{ {
calculate_progpath(calculate, config); _PyInitError err = calculate_program_name(calculate, config);
calculate_argv0_path(calculate, config); if (_Py_INIT_FAILED(err)) {
return err;
}
err = calculate_argv0_path(calculate, config->program_name);
if (_Py_INIT_FAILED(err)) {
return err;
}
calculate_read_pyenv(calculate); calculate_read_pyenv(calculate);
calculate_prefix(calculate, config);
calculate_zip_path(calculate, config); wchar_t prefix[MAXPATHLEN+1];
calculate_exec_prefix(calculate, config); memset(prefix, 0, sizeof(prefix));
calculate_prefix(calculate, prefix);
calculate_zip_path(calculate, prefix);
wchar_t exec_prefix[MAXPATHLEN+1];
memset(exec_prefix, 0, sizeof(exec_prefix));
calculate_exec_prefix(calculate, exec_prefix);
if ((!calculate->prefix_found || !calculate->exec_prefix_found) && if ((!calculate->prefix_found || !calculate->exec_prefix_found) &&
!Py_FrozenFlag) !Py_FrozenFlag)
@ -958,53 +986,105 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config)
"Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]\n"); "Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]\n");
} }
config->module_search_path = calculate_module_search_path(calculate, config); err = calculate_module_search_path(calculate, prefix, exec_prefix,
calculate_reduce_prefix(calculate, config); config);
calculate_reduce_exec_prefix(calculate, config); if (_Py_INIT_FAILED(err)) {
return err;
}
calculate_reduce_prefix(calculate, prefix);
config->prefix = _PyMem_RawWcsdup(prefix);
if (config->prefix == NULL) {
return _Py_INIT_NO_MEMORY();
}
calculate_reduce_exec_prefix(calculate, exec_prefix);
config->exec_prefix = _PyMem_RawWcsdup(exec_prefix);
if (config->exec_prefix == NULL) {
return _Py_INIT_NO_MEMORY();
}
return _Py_INIT_OK();
} }
static void static void
calculate_path(const _PyMainInterpreterConfig *main_config) pathconfig_clear(PyPathConfig *config)
{ {
_PyInitError err; #define CLEAR(ATTR) \
do { \
PyMem_RawFree(ATTR); \
ATTR = NULL; \
} while (0)
CLEAR(config->prefix);
CLEAR(config->exec_prefix);
CLEAR(config->program_name);
CLEAR(config->module_search_path);
#undef CLEAR
}
/* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix()
and Py_GetProgramFullPath() */
_PyInitError
_PyPathConfig_Init(const _PyMainInterpreterConfig *main_config)
{
if (path_config.module_search_path) {
/* Already initialized */
return _Py_INIT_OK();
}
PyCalculatePath calculate; PyCalculatePath calculate;
memset(&calculate, 0, sizeof(calculate)); memset(&calculate, 0, sizeof(calculate));
_PyMainInterpreterConfig tmp_config; _PyInitError err = calculate_init(&calculate, main_config);
int use_tmp = (main_config == NULL);
if (use_tmp) {
tmp_config = _PyMainInterpreterConfig_INIT;
err = _PyMainInterpreterConfig_ReadEnv(&tmp_config);
if (_Py_INIT_FAILED(err)) {
goto fatal_error;
}
main_config = &tmp_config;
}
err = calculate_init(&calculate, main_config);
if (_Py_INIT_FAILED(err)) { if (_Py_INIT_FAILED(err)) {
goto fatal_error; goto done;
} }
PyPathConfig new_path_config; PyPathConfig new_path_config;
memset(&new_path_config, 0, sizeof(new_path_config)); memset(&new_path_config, 0, sizeof(new_path_config));
calculate_path_impl(&calculate, &new_path_config); err = calculate_path_impl(&calculate, &new_path_config);
if (_Py_INIT_FAILED(err)) {
pathconfig_clear(&new_path_config);
goto done;
}
path_config = new_path_config; path_config = new_path_config;
err = _Py_INIT_OK();
if (use_tmp) { done:
_PyMainInterpreterConfig_Clear(&tmp_config);
}
calculate_free(&calculate); calculate_free(&calculate);
return; return err;
}
fatal_error:
if (use_tmp) { static void
_PyMainInterpreterConfig_Clear(&tmp_config); calculate_path(void)
{
_PyInitError err;
_PyMainInterpreterConfig config = _PyMainInterpreterConfig_INIT;
err = _PyMainInterpreterConfig_ReadEnv(&config);
if (!_Py_INIT_FAILED(err)) {
err = _PyPathConfig_Init(&config);
} }
calculate_free(&calculate); _PyMainInterpreterConfig_Clear(&config);
_Py_FatalInitError(err);
if (_Py_INIT_FAILED(err)) {
_Py_FatalInitError(err);
}
}
void
_PyPathConfig_Fini(void)
{
pathconfig_clear(&path_config);
} }
@ -1012,33 +1092,19 @@ fatal_error:
void void
Py_SetPath(const wchar_t *path) Py_SetPath(const wchar_t *path)
{ {
if (path_config.module_search_path != NULL) {
PyMem_RawFree(path_config.module_search_path);
path_config.module_search_path = NULL;
}
if (path == NULL) { if (path == NULL) {
pathconfig_clear(&path_config);
return; return;
} }
wchar_t *program_name = Py_GetProgramName(); PyPathConfig new_config;
wcsncpy(path_config.program_name, program_name, MAXPATHLEN); new_config.program_name = _PyMem_RawWcsdup(Py_GetProgramName());
path_config.exec_prefix[0] = path_config.prefix[0] = L'\0'; new_config.exec_prefix = _PyMem_RawWcsdup(L"");
size_t size = (wcslen(path) + 1) * sizeof(wchar_t); new_config.prefix = _PyMem_RawWcsdup(L"");
path_config.module_search_path = PyMem_RawMalloc(size); new_config.module_search_path = _PyMem_RawWcsdup(path);
if (path_config.module_search_path != NULL) {
wcscpy(path_config.module_search_path, path);
}
}
pathconfig_clear(&path_config);
wchar_t * path_config = new_config;
_Py_GetPathWithConfig(const _PyMainInterpreterConfig *main_config)
{
if (!path_config.module_search_path) {
calculate_path(main_config);
}
return path_config.module_search_path;
} }
@ -1046,7 +1112,7 @@ wchar_t *
Py_GetPath(void) Py_GetPath(void)
{ {
if (!path_config.module_search_path) { if (!path_config.module_search_path) {
calculate_path(NULL); calculate_path();
} }
return path_config.module_search_path; return path_config.module_search_path;
} }
@ -1056,7 +1122,7 @@ wchar_t *
Py_GetPrefix(void) Py_GetPrefix(void)
{ {
if (!path_config.module_search_path) { if (!path_config.module_search_path) {
calculate_path(NULL); calculate_path();
} }
return path_config.prefix; return path_config.prefix;
} }
@ -1066,7 +1132,7 @@ wchar_t *
Py_GetExecPrefix(void) Py_GetExecPrefix(void)
{ {
if (!path_config.module_search_path) { if (!path_config.module_search_path) {
calculate_path(NULL); calculate_path();
} }
return path_config.exec_prefix; return path_config.exec_prefix;
} }
@ -1076,7 +1142,7 @@ wchar_t *
Py_GetProgramFullPath(void) Py_GetProgramFullPath(void)
{ {
if (!path_config.module_search_path) { if (!path_config.module_search_path) {
calculate_path(NULL); calculate_path();
} }
return path_config.program_name; return path_config.program_name;
} }

View file

@ -38,14 +38,14 @@ extern "C" {
#define DECODE_LOCALE_ERR(NAME, LEN) \ #define DECODE_LOCALE_ERR(NAME, LEN) \
(((LEN) == -2) \ (((LEN) == -2) \
? _Py_INIT_USER_ERR("failed to decode " #NAME) \ ? _Py_INIT_USER_ERR("cannot decode " #NAME) \
: _Py_INIT_NO_MEMORY()) : _Py_INIT_NO_MEMORY())
#define SET_DECODE_ERROR(NAME, LEN) \ #define SET_DECODE_ERROR(NAME, LEN) \
do { \ do { \
if ((LEN) == (size_t)-2) { \ if ((LEN) == (size_t)-2) { \
pymain->err = _Py_INIT_USER_ERR("failed to decode " #NAME); \ pymain->err = _Py_INIT_USER_ERR("cannot decode " #NAME); \
} \ } \
else { \ else { \
pymain->err = _Py_INIT_NO_MEMORY(); \ pymain->err = _Py_INIT_NO_MEMORY(); \

View file

@ -117,9 +117,9 @@
#endif #endif
typedef struct { typedef struct {
wchar_t prefix[MAXPATHLEN+1]; wchar_t *prefix;
wchar_t program_name[MAXPATHLEN+1]; wchar_t *program_name;
wchar_t dllpath[MAXPATHLEN+1]; wchar_t *dll_path;
wchar_t *module_search_path; wchar_t *module_search_path;
} PyPathConfig; } PyPathConfig;
@ -483,24 +483,39 @@ done:
#endif /* Py_ENABLE_SHARED */ #endif /* Py_ENABLE_SHARED */
static void static _PyInitError
get_progpath(PyCalculatePath *calculate, PyPathConfig *config) get_dll_path(PyCalculatePath *calculate, PyPathConfig *config)
{ {
wchar_t *path = calculate->path_env; wchar_t dll_path[MAXPATHLEN+1];
memset(dll_path, 0, sizeof(dll_path));
#ifdef Py_ENABLE_SHARED #ifdef Py_ENABLE_SHARED
extern HANDLE PyWin_DLLhModule; extern HANDLE PyWin_DLLhModule;
/* static init of program_name ensures final char remains \0 */
if (PyWin_DLLhModule) { if (PyWin_DLLhModule) {
if (!GetModuleFileNameW(PyWin_DLLhModule, config->dllpath, MAXPATHLEN)) { if (!GetModuleFileNameW(PyWin_DLLhModule, dll_path, MAXPATHLEN)) {
config->dllpath[0] = 0; dll_path[0] = 0;
} }
} }
#else #else
config->dllpath[0] = 0; dll_path[0] = 0;
#endif #endif
if (GetModuleFileNameW(NULL, config->program_name, MAXPATHLEN)) {
return; config->dll_path = _PyMem_RawWcsdup(dll_path);
if (config->dll_path == NULL) {
return _Py_INIT_NO_MEMORY();
}
return _Py_INIT_OK();
}
static _PyInitError
get_program_name(PyCalculatePath *calculate, PyPathConfig *config)
{
wchar_t program_name[MAXPATHLEN+1];
memset(program_name, 0, sizeof(program_name));
if (GetModuleFileNameW(NULL, program_name, MAXPATHLEN)) {
goto done;
} }
/* 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
@ -514,9 +529,10 @@ get_progpath(PyCalculatePath *calculate, PyPathConfig *config)
if (wcschr(calculate->program_name, SEP)) if (wcschr(calculate->program_name, SEP))
#endif #endif
{ {
wcsncpy(config->program_name, calculate->program_name, MAXPATHLEN); wcsncpy(program_name, calculate->program_name, MAXPATHLEN);
} }
else if (path) { else if (calculate->path_env) {
wchar_t *path = calculate->path_env;
while (1) { while (1) {
wchar_t *delim = wcschr(path, DELIM); wchar_t *delim = wcschr(path, DELIM);
@ -524,29 +540,36 @@ get_progpath(PyCalculatePath *calculate, PyPathConfig *config)
size_t len = delim - path; size_t len = delim - path;
/* ensure we can't overwrite buffer */ /* ensure we can't overwrite buffer */
len = min(MAXPATHLEN,len); len = min(MAXPATHLEN,len);
wcsncpy(config->program_name, path, len); wcsncpy(program_name, path, len);
*(config->program_name + len) = '\0'; program_name[len] = '\0';
} }
else { else {
wcsncpy(config->program_name, path, MAXPATHLEN); wcsncpy(program_name, path, MAXPATHLEN);
} }
/* join() is safe for MAXPATHLEN+1 size buffer */ /* join() is safe for MAXPATHLEN+1 size buffer */
join(config->program_name, calculate->program_name); join(program_name, calculate->program_name);
if (exists(config->program_name)) { if (exists(program_name)) {
break; break;
} }
if (!delim) { if (!delim) {
config->program_name[0] = '\0'; program_name[0] = '\0';
break; break;
} }
path = delim + 1; path = delim + 1;
} }
} }
else { else {
config->program_name[0] = '\0'; program_name[0] = '\0';
} }
done:
config->program_name = _PyMem_RawWcsdup(program_name);
if (config->program_name == NULL) {
return _Py_INIT_NO_MEMORY();
}
return _Py_INIT_OK();
} }
@ -602,12 +625,13 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value)
} }
static wchar_t* static int
read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite) read_pth_file(PyPathConfig *config, wchar_t *prefix, const wchar_t *path,
int *isolated, int *nosite)
{ {
FILE *sp_file = _Py_wfopen(path, L"r"); FILE *sp_file = _Py_wfopen(path, L"r");
if (sp_file == NULL) { if (sp_file == NULL) {
return NULL; return 0;
} }
wcscpy_s(prefix, MAXPATHLEN+1, path); wcscpy_s(prefix, MAXPATHLEN+1, path);
@ -680,12 +704,13 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite)
} }
fclose(sp_file); fclose(sp_file);
return buf; config->module_search_path = buf;
return 1;
error: error:
PyMem_RawFree(buf); PyMem_RawFree(buf);
fclose(sp_file); fclose(sp_file);
return NULL; return 0;
} }
@ -704,8 +729,8 @@ calculate_init(PyCalculatePath *calculate,
static int static int
get_pth_filename(wchar_t *spbuffer, PyPathConfig *config) get_pth_filename(wchar_t *spbuffer, PyPathConfig *config)
{ {
if (config->dllpath[0]) { if (config->dll_path[0]) {
if (!change_ext(spbuffer, config->dllpath, L"._pth") && exists(spbuffer)) { if (!change_ext(spbuffer, config->dll_path, L"._pth") && exists(spbuffer)) {
return 1; return 1;
} }
} }
@ -719,7 +744,7 @@ get_pth_filename(wchar_t *spbuffer, PyPathConfig *config)
static int static int
calculate_pth_file(PyPathConfig *config) calculate_pth_file(PyPathConfig *config, wchar_t *prefix)
{ {
wchar_t spbuffer[MAXPATHLEN+1]; wchar_t spbuffer[MAXPATHLEN+1];
@ -727,13 +752,8 @@ calculate_pth_file(PyPathConfig *config)
return 0; return 0;
} }
config->module_search_path = read_pth_file(spbuffer, config->prefix, return read_pth_file(config, prefix, spbuffer,
&Py_IsolatedFlag, &Py_IsolatedFlag, &Py_NoSiteFlag);
&Py_NoSiteFlag);
if (!config->module_search_path) {
return 0;
}
return 1;
} }
@ -775,43 +795,34 @@ calculate_pyvenv_file(PyCalculatePath *calculate)
} }
#define INIT_ERR_BUFFER_OVERFLOW() _Py_INIT_ERR("buffer overflow")
static void static void
calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config, calculate_home_prefix(PyCalculatePath *calculate, wchar_t *prefix)
const _PyMainInterpreterConfig *main_config)
{ {
get_progpath(calculate, config);
/* program_name guaranteed \0 terminated in MAXPATH+1 bytes. */
wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, config->program_name);
reduce(calculate->argv0_path);
/* Search for a sys.path file */
if (calculate_pth_file(config)) {
return;
}
calculate_pyvenv_file(calculate);
/* Calculate zip archive path from DLL or exe path */
change_ext(calculate->zip_path,
config->dllpath[0] ? config->dllpath : config->program_name,
L".zip");
if (calculate->home == NULL || *calculate->home == '\0') { if (calculate->home == NULL || *calculate->home == '\0') {
if (calculate->zip_path[0] && exists(calculate->zip_path)) { if (calculate->zip_path[0] && exists(calculate->zip_path)) {
wcscpy_s(config->prefix, MAXPATHLEN+1, calculate->zip_path); wcscpy_s(prefix, MAXPATHLEN+1, calculate->zip_path);
reduce(config->prefix); reduce(prefix);
calculate->home = config->prefix; calculate->home = prefix;
} else if (search_for_prefix(config->prefix, calculate->argv0_path, LANDMARK)) { }
calculate->home = config->prefix; else if (search_for_prefix(prefix, calculate->argv0_path, LANDMARK)) {
calculate->home = prefix;
} }
else { else {
calculate->home = NULL; calculate->home = NULL;
} }
} }
else { else {
wcscpy_s(config->prefix, MAXPATHLEN+1, calculate->home); wcscpy_s(prefix, MAXPATHLEN+1, calculate->home);
} }
}
static _PyInitError
calculate_module_search_path(PyCalculatePath *calculate, PyPathConfig *config, wchar_t *prefix)
{
int skiphome = calculate->home==NULL ? 0 : 1; int skiphome = calculate->home==NULL ? 0 : 1;
#ifdef Py_ENABLE_SHARED #ifdef Py_ENABLE_SHARED
calculate->machine_path = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome); calculate->machine_path = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome);
@ -873,34 +884,34 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
fprintf(stderr, "Using default static path.\n"); fprintf(stderr, "Using default static path.\n");
config->module_search_path = PYTHONPATH; config->module_search_path = PYTHONPATH;
} }
return; return _Py_INIT_OK();
} }
start_buf = buf; start_buf = buf;
if (calculate->module_search_path_env) { if (calculate->module_search_path_env) {
if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->module_search_path_env)) { if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->module_search_path_env)) {
Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); return INIT_ERR_BUFFER_OVERFLOW();
} }
buf = wcschr(buf, L'\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
} }
if (calculate->zip_path[0]) { if (calculate->zip_path[0]) {
if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->zip_path)) { if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->zip_path)) {
Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); return INIT_ERR_BUFFER_OVERFLOW();
} }
buf = wcschr(buf, L'\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
} }
if (calculate->user_path) { if (calculate->user_path) {
if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->user_path)) { if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->user_path)) {
Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); return INIT_ERR_BUFFER_OVERFLOW();
} }
buf = wcschr(buf, L'\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
} }
if (calculate->machine_path) { if (calculate->machine_path) {
if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->machine_path)) { if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->machine_path)) {
Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); return INIT_ERR_BUFFER_OVERFLOW();
} }
buf = wcschr(buf, L'\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
@ -908,7 +919,7 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
if (calculate->home == NULL) { if (calculate->home == NULL) {
if (!skipdefault) { if (!skipdefault) {
if (wcscpy_s(buf, bufsz - (buf - start_buf), PYTHONPATH)) { if (wcscpy_s(buf, bufsz - (buf - start_buf), PYTHONPATH)) {
Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); return INIT_ERR_BUFFER_OVERFLOW();
} }
buf = wcschr(buf, L'\0'); buf = wcschr(buf, L'\0');
*buf++ = DELIM; *buf++ = DELIM;
@ -927,7 +938,7 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
} }
if (p[0] == '.' && is_sep(p[1])) { if (p[0] == '.' && is_sep(p[1])) {
if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->home)) { if (wcscpy_s(buf, bufsz - (buf - start_buf), calculate->home)) {
Py_FatalError("buffer overflow in getpathp.c's calculate_path()"); return INIT_ERR_BUFFER_OVERFLOW();
} }
buf = wcschr(buf, L'\0'); buf = wcschr(buf, L'\0');
p++; p++;
@ -957,7 +968,7 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
on the path, and that our 'prefix' directory is on the path, and that our 'prefix' directory is
the parent of that. the parent of that.
*/ */
if (config->prefix[0] == L'\0') { if (prefix[0] == L'\0') {
wchar_t lookBuf[MAXPATHLEN+1]; wchar_t lookBuf[MAXPATHLEN+1];
wchar_t *look = buf - 1; /* 'buf' is at the end of the buffer */ wchar_t *look = buf - 1; /* 'buf' is at the end of the buffer */
while (1) { while (1) {
@ -974,7 +985,7 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
lookBuf[nchars] = L'\0'; lookBuf[nchars] = L'\0';
/* Up one level to the parent */ /* Up one level to the parent */
reduce(lookBuf); reduce(lookBuf);
if (search_for_prefix(config->prefix, lookBuf, LANDMARK)) { if (search_for_prefix(prefix, lookBuf, LANDMARK)) {
break; break;
} }
/* If we are out of paths to search - give up */ /* If we are out of paths to search - give up */
@ -986,6 +997,59 @@ calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
} }
config->module_search_path = start_buf; config->module_search_path = start_buf;
return _Py_INIT_OK();
}
static _PyInitError
calculate_path_impl(PyCalculatePath *calculate, PyPathConfig *config,
const _PyMainInterpreterConfig *main_config)
{
_PyInitError err;
err = get_dll_path(calculate, config);
if (_Py_INIT_FAILED(err)) {
return err;
}
err = get_program_name(calculate, config);
if (_Py_INIT_FAILED(err)) {
return err;
}
/* program_name guaranteed \0 terminated in MAXPATH+1 bytes. */
wcscpy_s(calculate->argv0_path, MAXPATHLEN+1, config->program_name);
reduce(calculate->argv0_path);
wchar_t prefix[MAXPATHLEN+1];
memset(prefix, 0, sizeof(prefix));
/* Search for a sys.path file */
if (calculate_pth_file(config, prefix)) {
goto done;
}
calculate_pyvenv_file(calculate);
/* Calculate zip archive path from DLL or exe path */
change_ext(calculate->zip_path,
config->dll_path[0] ? config->dll_path : config->program_name,
L".zip");
calculate_home_prefix(calculate, prefix);
err = calculate_module_search_path(calculate, config, prefix);
if (_Py_INIT_FAILED(err)) {
return err;
}
done:
config->prefix = _PyMem_RawWcsdup(prefix);
if (config->prefix == NULL) {
return _Py_INIT_NO_MEMORY();
}
return _Py_INIT_OK();
} }
@ -996,47 +1060,85 @@ calculate_free(PyCalculatePath *calculate)
PyMem_RawFree(calculate->user_path); PyMem_RawFree(calculate->user_path);
} }
static void static void
calculate_path(const _PyMainInterpreterConfig *main_config) pathconfig_clear(PyPathConfig *config)
{ {
#define CLEAR(ATTR) \
do { \
PyMem_RawFree(ATTR); \
ATTR = NULL; \
} while (0)
CLEAR(config->prefix);
CLEAR(config->program_name);
CLEAR(config->dll_path);
CLEAR(config->module_search_path);
#undef CLEAR
}
/* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix()
and Py_GetProgramFullPath() */
_PyInitError
_PyPathConfig_Init(const _PyMainInterpreterConfig *main_config)
{
if (path_config.module_search_path) {
/* Already initialized */
return _Py_INIT_OK();
}
_PyInitError err; _PyInitError err;
PyCalculatePath calculate; PyCalculatePath calculate;
memset(&calculate, 0, sizeof(calculate)); memset(&calculate, 0, sizeof(calculate));
_PyMainInterpreterConfig tmp_config;
int use_tmp = (main_config == NULL);
if (use_tmp) {
tmp_config = _PyMainInterpreterConfig_INIT;
err = _PyMainInterpreterConfig_ReadEnv(&tmp_config);
if (_Py_INIT_FAILED(err)) {
goto fatal_error;
}
main_config = &tmp_config;
}
calculate_init(&calculate, main_config); calculate_init(&calculate, main_config);
PyPathConfig new_path_config; PyPathConfig new_path_config;
memset(&new_path_config, 0, sizeof(new_path_config)); memset(&new_path_config, 0, sizeof(new_path_config));
calculate_path_impl(&calculate, &new_path_config, main_config); err = calculate_path_impl(&calculate, &new_path_config, main_config);
if (_Py_INIT_FAILED(err)) {
goto done;
}
path_config = new_path_config; path_config = new_path_config;
err = _Py_INIT_OK();
if (use_tmp) { done:
_PyMainInterpreterConfig_Clear(&tmp_config); if (_Py_INIT_FAILED(err)) {
pathconfig_clear(&new_path_config);
} }
calculate_free(&calculate); calculate_free(&calculate);
return; return err;
fatal_error:
if (use_tmp) {
_PyMainInterpreterConfig_Clear(&tmp_config);
}
calculate_free(&calculate);
_Py_FatalInitError(err);
} }
static void
calculate_path(void)
{
_PyInitError err;
_PyMainInterpreterConfig config = _PyMainInterpreterConfig_INIT;
err = _PyMainInterpreterConfig_ReadEnv(&config);
if (!_Py_INIT_FAILED(err)) {
err = _PyPathConfig_Init(&config);
}
_PyMainInterpreterConfig_Clear(&config);
if (_Py_INIT_FAILED(err)) {
_Py_FatalInitError(err);
}
}
void
_PyPathConfig_Fini(void)
{
pathconfig_clear(&path_config);
}
/* External interface */ /* External interface */
@ -1044,31 +1146,21 @@ void
Py_SetPath(const wchar_t *path) Py_SetPath(const wchar_t *path)
{ {
if (path_config.module_search_path != NULL) { if (path_config.module_search_path != NULL) {
PyMem_RawFree(path_config.module_search_path); pathconfig_clear(&path_config);
path_config.module_search_path = NULL;
} }
if (path == NULL) { if (path == NULL) {
return; return;
} }
wchar_t *program_name = Py_GetProgramName(); PyPathConfig new_config;
wcsncpy(path_config.program_name, program_name, MAXPATHLEN); new_config.program_name = _PyMem_RawWcsdup(Py_GetProgramName());
path_config.prefix[0] = L'\0'; new_config.prefix = _PyMem_RawWcsdup(L"");
path_config.module_search_path = PyMem_RawMalloc((wcslen(path) + 1) * sizeof(wchar_t)); new_config.dll_path = _PyMem_RawWcsdup(L"");
if (path_config.module_search_path != NULL) { new_config.module_search_path = _PyMem_RawWcsdup(path);
wcscpy(path_config.module_search_path, path);
}
}
pathconfig_clear(&path_config);
wchar_t * path_config = new_config;
_Py_GetPathWithConfig(const _PyMainInterpreterConfig *main_config)
{
if (!path_config.module_search_path) {
calculate_path(main_config);
}
return path_config.module_search_path;
} }
@ -1076,7 +1168,7 @@ wchar_t *
Py_GetPath(void) Py_GetPath(void)
{ {
if (!path_config.module_search_path) { if (!path_config.module_search_path) {
calculate_path(NULL); calculate_path();
} }
return path_config.module_search_path; return path_config.module_search_path;
} }
@ -1086,7 +1178,7 @@ wchar_t *
Py_GetPrefix(void) Py_GetPrefix(void)
{ {
if (!path_config.module_search_path) { if (!path_config.module_search_path) {
calculate_path(NULL); calculate_path();
} }
return path_config.prefix; return path_config.prefix;
} }
@ -1103,7 +1195,7 @@ wchar_t *
Py_GetProgramFullPath(void) Py_GetProgramFullPath(void)
{ {
if (!path_config.module_search_path) { if (!path_config.module_search_path) {
calculate_path(NULL); calculate_path();
} }
return path_config.program_name; return path_config.program_name;
} }
@ -1129,7 +1221,7 @@ _Py_CheckPython3()
/* If there is a python3.dll next to the python3y.dll, /* If there is a python3.dll next to the python3y.dll,
assume this is a build tree; use that DLL */ assume this is a build tree; use that DLL */
wcscpy(py3path, path_config.dllpath); wcscpy(py3path, path_config.dll_path);
s = wcsrchr(py3path, L'\\'); s = wcsrchr(py3path, L'\\');
if (!s) { if (!s) {
s = py3path; s = py3path;

View file

@ -866,11 +866,6 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)
/* Now finish configuring the main interpreter */ /* Now finish configuring the main interpreter */
interp->config = *config; interp->config = *config;
/* GetPath may initialize state that _PySys_EndInit locks
in, and so has to be called first. */
/* TODO: Call Py_GetPath() in Py_ReadConfig, rather than here */
wchar_t *sys_path = _Py_GetPathWithConfig(&interp->config);
if (interp->core_config._disable_importlib) { if (interp->core_config._disable_importlib) {
/* Special mode for freeze_importlib: run with no import system /* Special mode for freeze_importlib: run with no import system
* *
@ -880,11 +875,20 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)
_PyRuntime.initialized = 1; _PyRuntime.initialized = 1;
return _Py_INIT_OK(); return _Py_INIT_OK();
} }
/* TODO: Report exceptions rather than fatal errors below here */ /* TODO: Report exceptions rather than fatal errors below here */
if (_PyTime_Init() < 0) if (_PyTime_Init() < 0)
return _Py_INIT_ERR("can't initialize time"); return _Py_INIT_ERR("can't initialize time");
/* GetPath may initialize state that _PySys_EndInit locks
in, and so has to be called first. */
err = _PyPathConfig_Init(&interp->config);
if (_Py_INIT_FAILED(err)) {
return err;
}
wchar_t *sys_path = Py_GetPath();
/* Finish setting up the sys module and import system */ /* Finish setting up the sys module and import system */
PySys_SetPath(sys_path); PySys_SetPath(sys_path);
if (_PySys_EndInit(interp->sysdict) < 0) if (_PySys_EndInit(interp->sysdict) < 0)
@ -1261,6 +1265,9 @@ Py_FinalizeEx(void)
#endif #endif
call_ll_exitfuncs(); call_ll_exitfuncs();
_PyPathConfig_Fini();
_PyRuntime_Finalize(); _PyRuntime_Finalize();
return status; return status;
} }
@ -1290,6 +1297,7 @@ new_interpreter(PyThreadState **tstate_p)
PyInterpreterState *interp; PyInterpreterState *interp;
PyThreadState *tstate, *save_tstate; PyThreadState *tstate, *save_tstate;
PyObject *bimod, *sysmod; PyObject *bimod, *sysmod;
_PyInitError err;
if (!_PyRuntime.initialized) { if (!_PyRuntime.initialized) {
return _Py_INIT_ERR("Py_Initialize must be called first"); return _Py_INIT_ERR("Py_Initialize must be called first");
@ -1325,10 +1333,13 @@ new_interpreter(PyThreadState **tstate_p)
interp->config = main_interp->config; interp->config = main_interp->config;
} }
err = _PyPathConfig_Init(&interp->config);
if (_Py_INIT_FAILED(err)) {
return err;
}
wchar_t *sys_path = Py_GetPath();
/* XXX The following is lax in error checking */ /* XXX The following is lax in error checking */
wchar_t *sys_path = _Py_GetPathWithConfig(&interp->config);
PyObject *modules = PyDict_New(); PyObject *modules = PyDict_New();
if (modules == NULL) { if (modules == NULL) {
return _Py_INIT_ERR("can't make modules dictionary"); return _Py_INIT_ERR("can't make modules dictionary");
@ -1359,7 +1370,6 @@ new_interpreter(PyThreadState **tstate_p)
if (bimod != NULL && sysmod != NULL) { if (bimod != NULL && sysmod != NULL) {
PyObject *pstderr; PyObject *pstderr;
_PyInitError err;
/* Set up a preliminary stderr printer until we have enough /* Set up a preliminary stderr printer until we have enough
infrastructure for the io module in place. */ infrastructure for the io module in place. */