Visitar URL original
gh-159008: Delay load user32.dll in libcrypto on Windows by azchohfi · Pull Request #159009 · python/cpython · GitHub
Skip to content

gh-159008: Delay load user32.dll in libcrypto on Windows - #159009

Open
azchohfi wants to merge 1 commit into
python:mainfrom
azchohfi:gh-159008-delayload-user32
Open

azchohfi wants to merge 1 commit into
python:mainfrom
azchohfi:gh-159008-delayload-user32

Conversation

@azchohfi

@azchohfi azchohfi commented Oct 8, 2026

Copy link
Copy Markdown

_hashlib and _ssl link libcrypto-3.dll. Its import table names three user32.dll functions:

  • GetProcessWindowStation and GetUserObjectInformationW, used by OPENSSL_isservice();
  • MessageBoxW, used by OPENSSL_showfatal().

Both are only reached from OPENSSL_die(), i.e. when OpenSSL aborts on an internal error. The
import is still resolved at load time, so import hashlib (and hmac, secrets, ssl,
asyncio, urllib.request, http.client ...) maps user32.dll, gdi32.dll, gdi32full.dll,
win32u.dll and imm32.dll into the process. A plain python.exe does not load any of them.
Since gh-155435, _ctypes no longer does either.

This links libcrypto with /DELAYLOAD:user32.dll. The three functions are then bound on first
call, on the abort path. The change is one line in PCbuild/openssl.vcxproj, so it takes effect
the next time the OpenSSL binaries in cpython-bin-deps are built with prepare_ssl.bat.

  • LDFLAGS replaces the VC targets' default /nologo /debug, which is unchanged from 3.0 to 3.5.
  • LDLIBS=delayimp.lib adds the delay-load helper; Configure still links the target's own
    ex_libs (ws2_32, gdi32, advapi32, crypt32, user32).
  • libssl gets the same flag but imports nothing from user32. It links with LNK4199, a
    "/DELAYLOAD:user32.dll ignored" warning, and no other change.

Built with this branch's openssl.vcxproj: OpenSSL 3.5.9, x64, Release; msbuild PCbuild\openssl.vcxproj as prepare_ssl.bat runs it, once without and once with the change.

  • dumpbin /dependents: USER32.dll moves to the delay-load table, and nothing else changes.
  • The result goes into a 3.15.0rc3 embeddable distribution, which uses OpenSSL 3.5.9:
    • import hashlib loads no user32/GDI DLL;
    • test_hashlib test_hmac test_ssl test_httplib test_urllib2_localnet test_asyncio.test_ssl test_asyncio.test_sslproto pass: 679 tests, 44 skipped.
  • OPENSSL_isservice() (exported), called from a small console program, still works: user32 is
    absent before the call and loaded by it, and the result (0) is the same as with the stock DLL.

Timing (one machine, i9-14900K, Windows 11; three copies of 3.15.0rc3 embeddable that differ
only in libcrypto/libssl; 20 interleaved passes, fresh process each; medians, paired
bootstrap 95% CIs):

python.org without this change with it difference
import _hashlib, in-process 4.94 ms 4.94 ms 2.92 ms −1.99 ms [−2.14, −1.95] (20/20 passes)
python -c "import hashlib", start to exit 27.0 ms 26.8 ms 24.7 ms −2.3 ms [−3.0, −1.5]
DLLs newly mapped by loading _hashlib.pyd 9 9 3 −6
import ssl after _hashlib 8.53 ms 8.59 ms 8.49 ms −0.1 [−0.3, +0.1]
python -c pass (control) 20.9 ms 20.9 ms 20.7 ms 0.0 [−0.5, +0.4]

On a 3.14.4 PGO build with OpenSSL 3.0.19, the same change measured −2.05 ms [−2.16, −1.95] for import _hashlib.

@python-cla-bot

python-cla-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

Comment thread PCbuild/openssl.vcxproj
if not exist "$(IntDir.TrimEnd('\'))" mkdir "$(IntDir.TrimEnd('\'))"
cd /D "$(IntDir.TrimEnd('\'))"
$(Perl) "$(opensslDir)\configure" $(OpenSSLPlatform) no-asm no-uplink
$(Perl) "$(opensslDir)\configure" $(OpenSSLPlatform) no-asm no-uplink "LDFLAGS=/nologo /debug /DELAYLOAD:user32.dll" LDLIBS=delayimp.lib

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use this file to build releases anymore, it's only really still here to avoid breaking people who may have integrated it into their own builds. This change won't have any effect - it needs to go upstream first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants