diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2023-01-24 17:04:00 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-24 17:04:00 (GMT) |
commit | 5a8ed019f9b826d2ba5766688d51005624cd0699 (patch) | |
tree | 80b117bb7041c2debe43c60c38c8f5345f09795f /PC | |
parent | bab79942c46436e0034c8a033a3c22974ddf6645 (diff) | |
download | cpython-5a8ed019f9b826d2ba5766688d51005624cd0699.zip cpython-5a8ed019f9b826d2ba5766688d51005624cd0699.tar.gz cpython-5a8ed019f9b826d2ba5766688d51005624cd0699.tar.bz2 |
gh-101135: Add backwards compatibility to Windows launcher for older 32-bit versions (GH-101138)
Python 2.x and up to 3.4 did not contain the "-32" in their registry name, so the 32 and 64-bit installs were treated equal. Since 3.5/PEP 514 this is no longer true, but we still want to detect the EOL versions correctly in case people are still using them.
Additionally, the code to replace a node with one with a lower sort key was buggy (wrong node chosen, replace never happened since parent was always NULL, replaced node never freed, etc)
(cherry picked from commit daec3a463c747c852d7ee91e82770fb1763d7d31)
Co-authored-by: Martin Boisvert <martin.boisvert@optelgroup.com>
Diffstat (limited to 'PC')
-rw-r--r-- | PC/launcher2.c | 155 |
1 files changed, 121 insertions, 34 deletions
diff --git a/PC/launcher2.c b/PC/launcher2.c index 8371c60..4c77ec0 100644 --- a/PC/launcher2.c +++ b/PC/launcher2.c @@ -1294,34 +1294,34 @@ _compareTag(const wchar_t *x, const wchar_t *y) int -addEnvironmentInfo(EnvironmentInfo **root, EnvironmentInfo *node) +addEnvironmentInfo(EnvironmentInfo **root, EnvironmentInfo* parent, EnvironmentInfo *node) { EnvironmentInfo *r = *root; if (!r) { *root = node; - node->parent = NULL; + node->parent = parent; return 0; } // Sort by company name switch (_compareCompany(node->company, r->company)) { case -1: - return addEnvironmentInfo(&r->prev, node); + return addEnvironmentInfo(&r->prev, r, node); case 1: - return addEnvironmentInfo(&r->next, node); + return addEnvironmentInfo(&r->next, r, node); case 0: break; } // Then by tag (descending) switch (_compareTag(node->tag, r->tag)) { case -1: - return addEnvironmentInfo(&r->next, node); + return addEnvironmentInfo(&r->next, r, node); case 1: - return addEnvironmentInfo(&r->prev, node); + return addEnvironmentInfo(&r->prev, r, node); case 0: break; } // Then keep the one with the lowest internal sort key - if (r->internalSortKey < node->internalSortKey) { + if (node->internalSortKey < r->internalSortKey) { // Replace the current node node->parent = r->parent; if (node->parent) { @@ -1334,9 +1334,16 @@ addEnvironmentInfo(EnvironmentInfo **root, EnvironmentInfo *node) freeEnvironmentInfo(node); return RC_INTERNAL_ERROR; } + } else { + // If node has no parent, then it is the root. + *root = node; } + node->next = r->next; node->prev = r->prev; + + debug(L"# replaced %s/%s/%i in tree\n", node->company, node->tag, node->internalSortKey); + freeEnvironmentInfo(r); } else { debug(L"# not adding %s/%s/%i to tree\n", node->company, node->tag, node->internalSortKey); return RC_DUPLICATE_ITEM; @@ -1392,6 +1399,100 @@ _combineWithInstallDir(const wchar_t **dest, const wchar_t *installDir, const wc } +bool +_isLegacyVersion(EnvironmentInfo *env) +{ + // Check if backwards-compatibility is required. + // Specifically PythonCore versions 2.X and 3.0 - 3.5 do not implement PEP 514. + if (0 != _compare(env->company, -1, L"PythonCore", -1)) { + return false; + } + + int versionMajor, versionMinor; + int n = swscanf_s(env->tag, L"%d.%d", &versionMajor, &versionMinor); + if (n != 2) { + debug(L"# %s/%s has an invalid version tag\n", env->company, env->tag); + return false; + } + + return versionMajor == 2 + || (versionMajor == 3 && versionMinor >= 0 && versionMinor <= 5); +} + +int +_registryReadLegacyEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *env, const wchar_t *fallbackArch) +{ + // Backwards-compatibility for PythonCore versions which do not implement PEP 514. + int exitCode = _combineWithInstallDir( + &env->executablePath, + env->installDir, + search->executable, + search->executableLength + ); + if (exitCode) { + return exitCode; + } + + if (search->windowed) { + exitCode = _registryReadString(&env->executableArgs, root, L"InstallPath", L"WindowedExecutableArguments"); + } + else { + exitCode = _registryReadString(&env->executableArgs, root, L"InstallPath", L"ExecutableArguments"); + } + if (exitCode) { + return exitCode; + } + + if (fallbackArch) { + copyWstr(&env->architecture, fallbackArch); + } else { + DWORD binaryType; + BOOL success = GetBinaryTypeW(env->executablePath, &binaryType); + if (!success) { + return RC_NO_PYTHON; + } + + switch (binaryType) { + case SCS_32BIT_BINARY: + copyWstr(&env->architecture, L"32bit"); + break; + case SCS_64BIT_BINARY: + copyWstr(&env->architecture, L"64bit"); + break; + default: + return RC_NO_PYTHON; + } + } + + if (0 == _compare(env->architecture, -1, L"32bit", -1)) { + size_t tagLength = wcslen(env->tag); + if (tagLength <= 3 || 0 != _compare(&env->tag[tagLength - 3], 3, L"-32", 3)) { + const wchar_t *rawTag = env->tag; + wchar_t *realTag = (wchar_t*) malloc(sizeof(wchar_t) * (tagLength + 4)); + if (!realTag) { + return RC_NO_MEMORY; + } + + int count = swprintf_s(realTag, tagLength + 4, L"%s-32", env->tag); + if (count == -1) { + free(realTag); + return RC_INTERNAL_ERROR; + } + + env->tag = realTag; + free((void*)rawTag); + } + } + + wchar_t buffer[MAXLEN]; + if (swprintf_s(buffer, MAXLEN, L"Python %s", env->tag)) { + copyWstr(&env->displayName, buffer); + } + + return 0; +} + + int _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *env, const wchar_t *fallbackArch) { @@ -1403,6 +1504,10 @@ _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *e return RC_NO_PYTHON; } + if (_isLegacyVersion(env)) { + return _registryReadLegacyEnvironment(search, root, env, fallbackArch); + } + // If pythonw.exe requested, check specific value if (search->windowed) { exitCode = _registryReadString(&env->executablePath, root, L"InstallPath", L"WindowedExecutablePath"); @@ -1425,6 +1530,11 @@ _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *e return exitCode; } + if (!env->executablePath) { + debug(L"# %s/%s has no executable path\n", env->company, env->tag); + return RC_NO_PYTHON; + } + exitCode = _registryReadString(&env->architecture, root, NULL, L"SysArchitecture"); if (exitCode) { return exitCode; @@ -1435,29 +1545,6 @@ _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *e return exitCode; } - // Only PythonCore entries will infer executablePath from installDir and architecture from the binary - if (0 == _compare(env->company, -1, L"PythonCore", -1)) { - if (!env->executablePath) { - exitCode = _combineWithInstallDir( - &env->executablePath, - env->installDir, - search->executable, - search->executableLength - ); - if (exitCode) { - return exitCode; - } - } - if (!env->architecture && env->executablePath && fallbackArch) { - copyWstr(&env->architecture, fallbackArch); - } - } - - if (!env->executablePath) { - debug(L"# %s/%s has no executable path\n", env->company, env->tag); - return RC_NO_PYTHON; - } - return 0; } @@ -1486,7 +1573,7 @@ _registrySearchTags(const SearchInfo *search, EnvironmentInfo **result, HKEY roo freeEnvironmentInfo(env); exitCode = 0; } else if (!exitCode) { - exitCode = addEnvironmentInfo(result, env); + exitCode = addEnvironmentInfo(result, NULL, env); if (exitCode) { freeEnvironmentInfo(env); if (exitCode == RC_DUPLICATE_ITEM) { @@ -1574,7 +1661,7 @@ appxSearch(const SearchInfo *search, EnvironmentInfo **result, const wchar_t *pa copyWstr(&env->displayName, buffer); } - int exitCode = addEnvironmentInfo(result, env); + int exitCode = addEnvironmentInfo(result, NULL, env); if (exitCode) { freeEnvironmentInfo(env); if (exitCode == RC_DUPLICATE_ITEM) { @@ -1612,7 +1699,7 @@ explicitOverrideSearch(const SearchInfo *search, EnvironmentInfo **result) if (exitCode) { goto abort; } - exitCode = addEnvironmentInfo(result, env); + exitCode = addEnvironmentInfo(result, NULL, env); if (exitCode) { goto abort; } @@ -1661,7 +1748,7 @@ virtualenvSearch(const SearchInfo *search, EnvironmentInfo **result) if (exitCode) { goto abort; } - exitCode = addEnvironmentInfo(result, env); + exitCode = addEnvironmentInfo(result, NULL, env); if (exitCode) { goto abort; } |