Skip to content

3.9.25.x: build ctypes against libffi 3.5+ on Windows (bpo-45898, gh-92356) - #119

Merged
icanhasmath merged 2 commits into
3.9.25.xfrom
3.9.25.x-ctypes-libffi35
Oct 29, 2026
Merged

icanhasmath merged 2 commits into
3.9.25.xfrom
3.9.25.x-ctypes-libffi35

Conversation

@icanhasmath

Copy link
Copy Markdown

Backports upstream's ctypes change from 3.11 so _ctypes builds on Windows against libffi 3.5 or later. The next release on this line (after 3.9.25.3) will carry it, and Platform can then drop inventory patch 29f5e6b0.

Why

  • From libffi 3.5, ffi.h always declares the ffi_type_* symbols __declspec(dllimport) under MSVC. The FFI_BUILDING define that _ctypes.vcxproj sets no longer turns that off.
  • cfield.c takes their addresses in a static table, which MSVC rejects for imported symbols: cfield.c(1475): error C2099: initializer is not a constant.
  • That's how the Platform's Windows build of 3.10.22.2 failed once it resolved shared/ffi 3.8.0. 3.9 has the same code, and its Platform build now uses libffi 3.8.0 too. 3.11+ isn't affected.

What

Testing

  • Windows x64, VS 2022 v143, on the EC2 test box, against the Platform's shared/ffi 3.8.0 artifact (libffi-8.dll): _ctypes builds, test_ctypes passes (498 tests, 31 skipped), and a probe of structures, c_wchar, callbacks through qsort and windll works.
  • Linux (system libffi 3.5.1): test_ctypes passes.
  • The same change is in Platform inventory now, as patch 29f5e6b0 on 3.9.25.3.

tiran and others added 2 commits October 29, 2026 13:05
…9791)

(cherry picked from commit 38f331d)

3.9.25.x: 3.9's format table keeps the 'u'/'U'/'Z' entries under
#ifdef CTYPES_UNICODE, so the conflict in formattable and in
_ctypes_get_fielddesc() was resolved with upstream's NULL-initialised
table and _ctypes_init_fielddesc() call, and the matching cases in
_ctypes_init_fielddesc() are guarded the same way. Needed on Windows once
the build uses libffi 3.5 or later, whose ffi.h always declares the
ffi_type_* symbols dllimport, so the static table no longer compiles
(C2099).
…on#92357)

38f331d introduced a delayed initialization routine to set up
ctypes formattable (`_ctypes_init_fielddesc`), but inadvertently
removed setting the `initialization` flag to 1 to avoid initting
each time.

(cherry picked from commit adcb6a6)
@icanhasmath icanhasmath mentioned this pull request Oct 29, 2026
@manoelc-dev
manoelc-dev self-requested a review October 29, 2026 22:37

@ezequielp-activestate ezequielp-activestate left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approving.

  • bpo-45898 and pythongh-92356 match upstream 3.11 (38f331d465, adcb6a6055) line for line. The one exception is the CTYPES_UNICODE guards on 3.9, and the conflict resolution there is correct: the 'u'/'U'/'Z' table entries and their _ctypes_init_fielddesc() cases are guarded the same way.
  • _ctypes_get_fielddesc() sets initialized, so the table is filled once.
  • Nothing else in Modules/_ctypes takes the address of an ffi_type_* in a static initializer.
  • Upstream has no later follow-ups to either change.

🟡 Non-blocking: besides dropping FFI_BUILDING, the _ctypes.vcxproj change defines USING_MALLOC_CLOSURE_DOT_C=1. On Windows, callback thunks then come from malloc_closure.c free-list pages rather than libffi's ffi_closure_alloc, because HAVE_FFI_CLOSURE_ALLOC isn't defined there. Upstream 3.11+ does the same, so this isn't a problem, but it is a runtime change beyond the build fix, and the release notes could mention it.

@manoelc-dev
manoelc-dev removed their request for review October 29, 2026 22:43
@icanhasmath
icanhasmath merged commit a67b716 into 3.9.25.x Oct 29, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants