summaryrefslogtreecommitdiffstats
path: root/PC
diff options
context:
space:
mode:
authorSteve Dower <steve.dower@python.org>2019-06-29 21:28:59 (GMT)
committerGitHub <noreply@github.com>2019-06-29 21:28:59 (GMT)
commit323e743d4879f1cd861d0b252775797fb7938755 (patch)
treecfaccee98a1695fabc022c04450b972e4f79071d /PC
parent0cba121029bae0a891b02c493cb77633620701be (diff)
downloadcpython-323e743d4879f1cd861d0b252775797fb7938755.zip
cpython-323e743d4879f1cd861d0b252775797fb7938755.tar.gz
cpython-323e743d4879f1cd861d0b252775797fb7938755.tar.bz2
bpo-37369: Fix initialization of sys members when launched via an app container (GH-14467)
sys._base_executable is now always defined on all platforms, and can be overridden through configuration. Also adds test.support.PythonSymlink to encapsulate platform-specific logic for symlinking sys.executable
Diffstat (limited to 'PC')
-rw-r--r--PC/getpathp.c20
-rw-r--r--PC/python_uwp.cpp287
2 files changed, 176 insertions, 131 deletions
diff --git a/PC/getpathp.c b/PC/getpathp.c
index e86cf13..7465d31 100644
--- a/PC/getpathp.c
+++ b/PC/getpathp.c
@@ -537,14 +537,28 @@ get_program_full_path(const PyConfig *config,
wchar_t program_full_path[MAXPATHLEN+1];
memset(program_full_path, 0, sizeof(program_full_path));
+ if (!GetModuleFileNameW(NULL, program_full_path, MAXPATHLEN)) {
+ /* GetModuleFileName should never fail when passed NULL */
+ return _PyStatus_ERR("Cannot determine program path");
+ }
+
/* The launcher may need to force the executable path to a
* different environment, so override it here. */
pyvenv_launcher = _wgetenv(L"__PYVENV_LAUNCHER__");
if (pyvenv_launcher && pyvenv_launcher[0]) {
+ /* If overridden, preserve the original full path */
+ pathconfig->base_executable = PyMem_RawMalloc(
+ sizeof(wchar_t) * (MAXPATHLEN + 1));
+ PyStatus status = canonicalize(pathconfig->base_executable,
+ program_full_path);
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
+
wcscpy_s(program_full_path, MAXPATHLEN+1, pyvenv_launcher);
- } else if (!GetModuleFileNameW(NULL, program_full_path, MAXPATHLEN)) {
- /* GetModuleFileName should never fail when passed NULL */
- return _PyStatus_ERR("Cannot determine program path");
+ /* bpo-35873: Clear the environment variable to avoid it being
+ * inherited by child processes. */
+ _wputenv_s(L"__PYVENV_LAUNCHER__", L"");
}
pathconfig->program_full_path = PyMem_RawMalloc(
diff --git a/PC/python_uwp.cpp b/PC/python_uwp.cpp
index dd1edde..2352f45 100644
--- a/PC/python_uwp.cpp
+++ b/PC/python_uwp.cpp
@@ -6,6 +6,9 @@
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <shellapi.h>
+#include <shlobj.h>
+
+#include <string>
#include <winrt\Windows.ApplicationModel.h>
#include <winrt\Windows.Storage.h>
@@ -24,192 +27,220 @@ const wchar_t *PROGNAME = L"python.exe";
#endif
#endif
-static void
-set_user_base()
+static std::wstring
+get_user_base()
{
- wchar_t envBuffer[2048];
try {
const auto appData = winrt::Windows::Storage::ApplicationData::Current();
if (appData) {
const auto localCache = appData.LocalCacheFolder();
if (localCache) {
auto path = localCache.Path();
- if (!path.empty() &&
- !wcscpy_s(envBuffer, path.c_str()) &&
- !wcscat_s(envBuffer, L"\\local-packages")
- ) {
- _wputenv_s(L"PYTHONUSERBASE", envBuffer);
+ if (!path.empty()) {
+ return std::wstring(path) + L"\\local-packages";
}
}
}
} catch (...) {
}
+ return std::wstring();
}
-static const wchar_t *
-get_argv0(const wchar_t *argv0)
+static std::wstring
+get_package_family()
{
- winrt::hstring installPath;
- const wchar_t *launcherPath;
- wchar_t *buffer;
- size_t len;
-
- launcherPath = _wgetenv(L"__PYVENV_LAUNCHER__");
- if (launcherPath && launcherPath[0]) {
- len = wcslen(launcherPath) + 1;
- buffer = (wchar_t *)malloc(sizeof(wchar_t) * len);
- if (!buffer) {
- Py_FatalError("out of memory");
- return NULL;
- }
- if (wcscpy_s(buffer, len, launcherPath)) {
- Py_FatalError("failed to copy to buffer");
- return NULL;
+ try {
+ const auto package = winrt::Windows::ApplicationModel::Package::Current();
+ if (package) {
+ const auto id = package.Id();
+ if (id) {
+ return std::wstring(id.FamilyName());
+ }
}
- return buffer;
}
+ catch (...) {
+ }
+
+ return std::wstring();
+}
+static std::wstring
+get_package_home()
+{
try {
const auto package = winrt::Windows::ApplicationModel::Package::Current();
if (package) {
- const auto install = package.InstalledLocation();
- if (install) {
- installPath = install.Path();
+ const auto path = package.InstalledLocation();
+ if (path) {
+ return std::wstring(path.Path());
}
}
}
catch (...) {
}
- if (!installPath.empty()) {
- len = installPath.size() + wcslen(PROGNAME) + 2;
- } else {
- len = wcslen(argv0) + wcslen(PROGNAME) + 1;
- }
+ return std::wstring();
+}
- buffer = (wchar_t *)malloc(sizeof(wchar_t) * len);
- if (!buffer) {
- Py_FatalError("out of memory");
- return NULL;
- }
+static PyStatus
+set_process_name(PyConfig *config)
+{
+ PyStatus status = PyStatus_Ok();
+ std::wstring executable;
- if (!installPath.empty()) {
- if (wcscpy_s(buffer, len, installPath.c_str())) {
- Py_FatalError("failed to copy to buffer");
- return NULL;
- }
- if (wcscat_s(buffer, len, L"\\")) {
- Py_FatalError("failed to concatenate backslash");
- return NULL;
- }
- } else {
- if (wcscpy_s(buffer, len, argv0)) {
- Py_FatalError("failed to copy argv[0]");
- return NULL;
- }
+ const auto home = get_package_home();
+ const auto family = get_package_family();
- wchar_t *name = wcsrchr(buffer, L'\\');
- if (name) {
- name[1] = L'\0';
- } else {
- buffer[0] = L'\0';
+ if (!family.empty()) {
+ PWSTR localAppData;
+ if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0,
+ NULL, &localAppData))) {
+ executable = std::wstring(localAppData)
+ + L"\\Microsoft\\WindowsApps\\"
+ + family
+ + L"\\"
+ + PROGNAME;
+
+ CoTaskMemFree(localAppData);
}
}
- if (wcscat_s(buffer, len, PROGNAME)) {
- Py_FatalError("failed to concatenate program name");
- return NULL;
+ /* Only use module filename if we don't have a home */
+ if (home.empty() && executable.empty()) {
+ executable.resize(MAX_PATH);
+ while (true) {
+ DWORD len = GetModuleFileNameW(
+ NULL, executable.data(), (DWORD)executable.size());
+ if (len == 0) {
+ executable.clear();
+ break;
+ } else if (len == executable.size() &&
+ GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ executable.resize(len * 2);
+ } else {
+ executable.resize(len);
+ break;
+ }
+ }
}
- return buffer;
-}
-
-static wchar_t *
-get_process_name()
-{
- DWORD bufferLen = MAX_PATH;
- DWORD len = bufferLen;
- wchar_t *r = NULL;
-
- while (!r) {
- r = (wchar_t *)malloc(bufferLen * sizeof(wchar_t));
- if (!r) {
- Py_FatalError("out of memory");
- return NULL;
+ if (!home.empty()) {
+ status = PyConfig_SetString(config, &config->home, home.c_str());
+ if (PyStatus_Exception(status)) {
+ return status;
}
- len = GetModuleFileNameW(NULL, r, bufferLen);
- if (len == 0) {
- free((void *)r);
- return NULL;
- } else if (len == bufferLen &&
- GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
- free(r);
- r = NULL;
- bufferLen *= 2;
+ }
+
+ const wchar_t *launcherPath = _wgetenv(L"__PYVENV_LAUNCHER__");
+ if (launcherPath) {
+ if (!executable.empty()) {
+ status = PyConfig_SetString(config, &config->base_executable,
+ executable.c_str());
+ if (PyStatus_Exception(status)) {
+ return status;
+ }
}
+
+ status = PyConfig_SetString(
+ config, &config->executable, launcherPath);
+
+ /* bpo-35873: Clear the environment variable to avoid it being
+ * inherited by child processes. */
+ _wputenv_s(L"__PYVENV_LAUNCHER__", L"");
+ } else if (!executable.empty()) {
+ status = PyConfig_SetString(
+ config, &config->executable, executable.c_str());
}
- return r;
+ return status;
}
int
wmain(int argc, wchar_t **argv)
{
- const wchar_t **new_argv;
- int new_argc;
- const wchar_t *exeName;
+ PyStatus status;
- new_argc = argc;
- new_argv = (const wchar_t**)malloc(sizeof(wchar_t *) * (argc + 2));
- if (new_argv == NULL) {
- Py_FatalError("out of memory");
- return -1;
+ PyPreConfig preconfig;
+ PyConfig config;
+
+ PyPreConfig_InitPythonConfig(&preconfig);
+ status = Py_PreInitializeFromArgs(&preconfig, argc, argv);
+ if (PyStatus_Exception(status)) {
+ goto fail_without_config;
}
- exeName = get_process_name();
+ status = PyConfig_InitPythonConfig(&config);
+ if (PyStatus_Exception(status)) {
+ goto fail_without_config;
+ }
- new_argv[0] = get_argv0(exeName ? exeName : argv[0]);
- for (int i = 1; i < argc; ++i) {
- new_argv[i] = argv[i];
+ status = PyConfig_SetArgv(&config, argc, argv);
+ if (PyStatus_Exception(status)) {
+ goto fail;
}
- set_user_base();
+ status = set_process_name(&config);
+ if (PyStatus_Exception(status)) {
+ goto fail;
+ }
- if (exeName) {
- const wchar_t *p = wcsrchr(exeName, L'\\');
- if (p) {
- const wchar_t *moduleName = NULL;
- if (*p++ == L'\\') {
- if (wcsnicmp(p, L"pip", 3) == 0) {
- moduleName = L"pip";
- /* No longer required when pip 19.1 is added */
- _wputenv_s(L"PIP_USER", L"true");
- } else if (wcsnicmp(p, L"idle", 4) == 0) {
- moduleName = L"idlelib";
- }
- }
+ const wchar_t *p = _wgetenv(L"PYTHONUSERBASE");
+ if (!p || !*p) {
+ _wputenv_s(L"PYTHONUSERBASE", get_user_base().c_str());
+ }
- if (moduleName) {
- new_argc += 2;
- for (int i = argc; i >= 1; --i) {
- new_argv[i + 2] = new_argv[i];
- }
- new_argv[1] = L"-m";
- new_argv[2] = moduleName;
+ p = wcsrchr(argv[0], L'\\');
+ if (!p) {
+ p = argv[0];
+ }
+ if (p) {
+ if (*p == L'\\') {
+ p++;
+ }
+
+ const wchar_t *moduleName = NULL;
+ if (wcsnicmp(p, L"pip", 3) == 0) {
+ moduleName = L"pip";
+ /* No longer required when pip 19.1 is added */
+ _wputenv_s(L"PIP_USER", L"true");
+ } else if (wcsnicmp(p, L"idle", 4) == 0) {
+ moduleName = L"idlelib";
+ }
+
+ if (moduleName) {
+ status = PyConfig_SetString(&config, &config.run_module, moduleName);
+ if (PyStatus_Exception(status)) {
+ goto fail;
+ }
+ status = PyConfig_SetString(&config, &config.run_filename, NULL);
+ if (PyStatus_Exception(status)) {
+ goto fail;
+ }
+ status = PyConfig_SetString(&config, &config.run_command, NULL);
+ if (PyStatus_Exception(status)) {
+ goto fail;
}
}
}
- /* Override program_full_path from here so that
- sys.executable is set correctly. */
- _Py_SetProgramFullPath(new_argv[0]);
-
- int result = Py_Main(new_argc, (wchar_t **)new_argv);
+ status = Py_InitializeFromConfig(&config);
+ if (PyStatus_Exception(status)) {
+ goto fail;
+ }
+ PyConfig_Clear(&config);
- free((void *)exeName);
- free((void *)new_argv);
+ return Py_RunMain();
- return result;
+fail:
+ PyConfig_Clear(&config);
+fail_without_config:
+ if (PyStatus_IsExit(status)) {
+ return status.exitcode;
+ }
+ assert(PyStatus_Exception(status));
+ Py_ExitStatusException(status);
+ /* Unreachable code */
+ return 0;
}
#ifdef PYTHONW