-
-
Notifications
You must be signed in to change notification settings - Fork 31.6k
bdist_wininst created binaries fail to start and find 32bit Pythons #70259
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Binaries created by bdist_wininst fail on 3.5+ for 2 reasons:
This patch:
With these patches I can successfully get a pywin32 build working and installing. Steve (or anyone), what do you think? (Note that the attached patch does *not* include a newly built wininst-14.exe, but that would obviously need to be updated before checking in.) |
Looks good to me. Feel free to check it in, Mark, or one of us will get to it if you're not set up for committing right now. |
I would call SetDllDirectory instead of changing the current directory. This replaces the current directory in the DLL search. Then call SetDllDirectory(NULL) to restore the default before returning. When you say "the CRT assembly", you're talking about vcruntime140.dll, right? This module implements exceptions, setjmp/longjmp, and other functions that are closely coupled with the VC++ version, but most of the universal CRT is implemented in the system DLL ucrtbase.dll. vcruntime was initially linked statically everywhere, but that was a problem for extension modules, since each instance was taking a fiber locale storage slot. However, it really should be static for the bdist_wininst installer. I believe Steve had the link configuration customized as a partially static build that linked dynamically with ucrtbase.dll. This benefits from continuous CRT bug fixes and security updates. To configure this he added ucrt[d].lib as a dependency and ignored the default library libucrt[d].lib. See the following diff for the changes that were made to revert this:
|
In this case, it needs to load vcruntime for the python##.dll, so linking isn't going to make any difference. We need to statically link the loader, since it will be run independently and can't have any dependencies, but when it finds a Python install and loads the DLL directly it's not finding the vcruntime adjacent to the DLL. We'd have to statically link python##.dll. SetDllDirectory would also work, though it's a little more complicated to get right. It's probably worth it here though to set the search path around the load in this case, as we know that nobody else is expecting the value to not change. However, it may break other loads if python##.dll calls it or makes assumptions about the search path (which it almost certainly does). Setting the working directory is likely to lead to a more reliable initial state. |
I was talking about the partially static build that you used for wininst-14.0-amd64.exe in rc3, in which vcruntime is linked statically but ucrt is linked dynamically (actually to the api-ms-win-crt-* API sets). But is there a bad assumption there? I was only thinking about installing to systems with Python 3.5+, on which ucrtbase.dll is guaranteed to be in System32, but this installer should work for older systems that don't have the universal CRT update, right?
I don't understand. It would be pretty broken if python##.dll depends on the current directory. All SetDllDirectory does is swap in the target directory in place of the current directory in the DLL search path. I made the suggestion because it's cleaner to surgically change only what the system loader sees, rather than changing the current directory, which affects everything. The LoadLibrary docs recommend using SetDllDirectory instead of changing the current directory. Using AddDllDirectory would be better, but that's only available on updated Vista/7 systems (KB2533623). |
Steve, I think I understand the linking problem now -- in terms of the bad assumption I mentioned in the previous message. Mark said the "built binary links against the DLL version of the CRT", but I just checked in 3.5.1 that you actually didn't switch that one to link against vcruntime140.dll like you did with everything else, so he's only referring to the api-set-ms-win-crt dependencies. This would only fail on systems that don't have the universal CRT update. I thought he meant the executable was typically failing on all systems that don't have Visual Studio, which installs vcruntime140.dll in System32. |
Yeah, I didn't dig too much further here, but I'm fairly sure that "static crt" has been a thing for quite a while now for that stub (there are comments about that around the SetStdHandle calls in that file). I suspect it was accidentally lost in one of the build system fixups that happened (which seem great and a vast improvement!) |
Ultimately, launching python.exe is better than loading python##.dll here because it avoids DLL planting vulnerabilities, but I'm honestly a little surprised still that LoadLibrary won't resolve vcruntime in this case. Been a while since I looked, and I haven't had a chance to check for this yet, but why isn't the directory containing the loaded DLL searched for dependencies? |
That's possible. The loader provides several ways to go about solving this problem. The directory of the DLL can be added to the search path if you use LoadLibraryEx with the flag LOAD_WITH_ALTERED_SEARCH_PATH and use an absolute path. Python already does this for loading extension modules. If we didn't have to worry about older systems, in Windows 8/10 (and Vista/7 with KB2533623), the loader supports a set of flags that give detailed control of the DLL path, including LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR. Individual directories can be added via AddDllDirectory and enabled via the flag LOAD_LIBRARY_SEARCH_USER_DIRS. Default flags can be set via SetDefaultDllDirectories, which affects LoadLibrary as well as LoadLibraryEx. On a related note, it would be nice to modify ctypes to call LoadLibraryEx instead of LoadLibrary. If the flags value is 0 the two calls are identical, so it wouldn't be a disruptive change. The existing dlopen "mode" parameter can be used for the flags, since it isn't used on Windows currently. |
That sounds like the better fix then. I thought there was something along those lines available. We already use the full path to load it - can someone test this change? If not I'll give it a go later today. |
That does work. I didn't do it that way initially as I felt your earlier comment:
Was an additional nice outcome of just changing the cwd. This patch does the LoadLibraryEx() and works (but obviously leaves the CWD being the downloaded directory, probably %temp%) I'll check this in once I get the green-light, thanks. |
welp, I hadn't actually tested the patch on x64 yet ;)
should read:
WIN_64 is a Python invented name and this stub doesn't Python pull the headers in... |
The downside of the preprocessor - no errors when you spell an ifdef wrong ;) It looks good to me. |
New changeset daa6fdaf9835 by Steve Dower in branch '3.5': New changeset db74f3a4cbeb by Steve Dower in branch 'default': |
Applied the patch and rebuilt the stubs, so this will show up in 3.5.2 and 3.6. |
The applied patch breaks bdist_wininst installers for 64-bit Python. See <http://bugs.python.org/issue28680\>. |
Looks like I acknowledged the error in the patch and then didn't fix it when I applied it. The change needed here is what Mark describes above, plus recompiling the executable stubs. Or alternatively, I can probably just edit out the bytes in the existing stub for 3.6.0 and fix it properly for 3.6.1. Ned - thoughts? This regressed from 3.4 and has not worked properly for both architectures (simultaneously) since 3.5. |
Since we are two days from the final release, the fix requires rebuilding and replacing a binary file in the source repo, and you state (in related bpo-28680): "Considering we've gone through all of 3.5 and 3.6 with very few people noticing (and as far as I'm aware, completely able to fix it themselves), it may not make the initial 3.6 release.", I would prefer to hold this for 3.6.1. |
New changeset c3da1ee47e6b by Steve Dower in branch '3.5': New changeset 0528a6743018 by Steve Dower in branch '3.6': New changeset 4e9d899fcb65 by Steve Dower in branch 'default': |
Fixed for 3.5.3, 3.6.1 and default. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: