Skip to content

gh-153711: Guard dup3/pipe2 with __builtin_available on Apple platforms#154718

Closed
Vamsi-klu wants to merge 2 commits into
python:mainfrom
Vamsi-klu:fix-gh153711-macos-dup3-pipe2-weaklink
Closed

gh-153711: Guard dup3/pipe2 with __builtin_available on Apple platforms#154718
Vamsi-klu wants to merge 2 commits into
python:mainfrom
Vamsi-klu:fix-gh153711-macos-dup3-pipe2-weaklink

Conversation

@Vamsi-klu

Copy link
Copy Markdown

Summary

Fix gh-153711 (deferred-blocker): when CPython is built with an Xcode 27 SDK, dup3 / pipe2 are detected at configure time but only exist at runtime on macOS / iOS 27+. On older OSes they bind as weak_import NULL and the first os.pipe() / non-inheritable os.dup2() jumps to address 0.


What the issue is

  1. Xcode 27 SDKs annotate dup3/pipe2 with __API_AVAILABLE(macos(27.0), iOS(27.0), …).
  2. AC_CHECK_FUNCS synthesizes its own char dup3(); prototype, ignores availability, links against libSystem.tbd, and defines HAVE_DUP3 / HAVE_PIPE2.
  3. Modules/posixmodule.c then calls them unconditionally inside os_dup2_impl / os_pipe_impl / os_pipe2_impl.
  4. With MACOSX_DEPLOYMENT_TARGET < 27, the symbols are weak; on macOS 26 they are NULL → EXC_BAD_ACCESS.
  5. os.pipe() is on the hot path of subprocess, multiprocessing, and asyncio — effectively a total-loss crash for python.org-style builds.

iOS was already excluded from the configure check (gh-150443 / #150444). macOS was not. The issue body already points at the gh-97897 (mkfifoat/mknodat) weak-linking pattern.


Why I solved it that way

  1. Runtime __builtin_available guards, not configure hacks — configure cannot see availability attributes, and we still want the symbols on macOS 27+.
  2. Reuse the existing three-arm HAVE_*_RUNTIME machinery in posixmodule.c (modern / Xcode≤8 / non-Apple) documented in Mac/README.rst. Omitting any arm breaks the build.
  3. Sole-expression if (HAVE_X_RUNTIME) — Apple's compiler rejects if (!HAVE_X_RUNTIME).
  4. Latch dup3_works = 0 when unavailable so the existing dup2+FD_CLOEXEC fallback runs this call and every later call without re-probing.
  5. Seed res = -1; errno = ENOSYS before the pipe2 probe so the existing ENOSYS → pipe() fallback still runs when the symbol is missing (uninitialized res/errno would be a footgun).
  6. Pop os.pipe2 from the module dict when unavailable (same idiom as pwritev/preadv) because os_pipe2_impl has no fallback and would crash on direct call. Existing tests already hasattr(os, "pipe2").
  7. Omit visionOS from __builtin_available — no other macro in the block names it; pre-Xcode-15 clang rejects the spelling.
  8. Honest verification limit: this environment is Linux. Code mirrors Prevent segfaults by adding macOS weaklinking for mkfifoat and mknodat system calls added in macOS 13 Ventura #97897; an OS-mac core dev with Xcode 27 should confirm on macOS 26.

How I did it

Area Change
Modules/posixmodule.c HAVE_DUP3_RUNTIME / HAVE_PIPE2_RUNTIME in all 3 arms; guard dup3/pipe2 call sites; pop pipe2 at exec
Lib/test/test_os/test_posix.py TestPosixWeaklinking.test_pipe2 / test_dup3
Doc/library/os.rst os.pipe2 availability notes macOS/iOS ≥ 27
Misc/NEWS.d/next/macOS/ blurb for gh-153711

Impact

  • Unblocks building with Xcode 27 SDKs while deploying to macOS < 27.
  • On Linux/non-Apple, macros are 1zero codegen change (constant-folded).
  • On macOS ≥ 27, behavior unchanged (fast path still used).
  • Deferred-blocker across 3.13–3.16 — backports appropriate after OS-mac review.

Testing plan

  • Linux debug build + ./python -m test test_os.test_posix — PASS (weaklinking class skipped on non-macOS, as designed).
  • Smoke: os.pipe() / os.dup2(..., inheritable=False) on Linux — OK.
  • Needed from reviewer / buildbot: macOS 26 host, Xcode 27 SDK, deployment target < 27:
    • Before: crash on os.pipe() / os.pipe2 / non-inheritable dup2.
    • After: os.pipe() works via fallback; hasattr(os, "pipe2") is False; TestPosixWeaklinking assertions hold.
  • macOS 27+ : pipe2 present, weaklinking tests assert attrs exist.
  • CI: macOS jobs (will not fully exercise the Xcode 27 × older OS matrix).

Everything else


Requested reviewers (subject-matter experts)

Could the following SMEs take a look when convenient (I cannot formally request reviews from this fork account):

Thank you!

…latforms

Add HAVE_DUP3_RUNTIME / HAVE_PIPE2_RUNTIME weak-linking so Xcode 27 SDKs
do not crash on macOS < 27 when the symbols are weak_import NULL.
@python-cla-bot

python-cla-bot Bot commented Jul 26, 2026

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e5fbe3bb60

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Doc/library/os.rst Outdated

.. availability:: Unix, not WASI, not macOS, not iOS.
.. availability:: Unix, not WASI. Availability on macOS requires macOS 27.0
or later; availability on iOS requires iOS 27.0 or later.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep pipe2 documented as unavailable on iOS

The new iOS availability claim is inaccurate even on iOS 27: configure.ac:5526-5532 unconditionally skips the pipe2 feature check whenever ac_sys_system is iOS, so HAVE_PIPE2 remains undefined and the module never exports os.pipe2. Either retain not iOS here or change the iOS configure policy to enable the function where supported.

Useful? React with 👍 / 👎.

Comment thread Modules/posixmodule.c
#endif

#if defined(HAVE_PIPE2)
if (HAVE_PIPE2_RUNTIME) {} else {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Guard the remaining direct pipe2 call at compile time

When building with an Xcode 27 SDK for a macOS deployment target below 27, removing pipe2 from the module dictionary happens too late to make the build succeed: os_pipe2_impl still calls the availability-annotated pipe2 unguarded at Modules/posixmodule.c:12861, while configure.ac:2797-2802 promotes Clang's unguarded-availability diagnostic to an error. The call needs a lexical availability guard or the same targeted diagnostic suppression used for the runtime-removed preadv/pwritev methods.

Useful? React with 👍 / 👎.

The availability extension only accepts comma-separated known platforms
(optionally with 'not ' / '>= version'). Free-form prose after 'not WASI.'
was parsed as an unknown platform and failed Docs EPUB/doctest with
warnings-as-errors.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 548b366f3b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Doc/library/os.rst
respectively.

.. availability:: Unix, not WASI, not macOS, not iOS.
.. availability:: Unix, not WASI, macOS >= 27.0, iOS >= 27.0.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Correct the iOS availability claim

The documentation promises os.pipe2 on iOS 27+, but configure.ac deliberately skips the AC_CHECK_FUNCS invocation containing pipe2 whenever ac_sys_system is iOS (lines 5526–5532). Consequently HAVE_PIPE2 is never defined and the method is not compiled or exported on any iOS version; either enable the configure check for supported iOS versions or continue documenting this as unavailable on iOS.

Useful? React with 👍 / 👎.

@read-the-docs-community

Copy link
Copy Markdown

Documentation build overview

📚 cpython-previews | 🛠️ Build #33762150 | 📁 Comparing 548b366 against main (f5f5059)

  🔍 Preview build  

2 files changed
± library/os.html
± whatsnew/changelog.html

@Vamsi-klu
Vamsi-klu marked this pull request as draft July 26, 2026 08:01
@Vamsi-klu

Copy link
Copy Markdown
Author

Closing this PR. Thank you for the review attention.

@Vamsi-klu Vamsi-klu closed this Jul 26, 2026
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.

macOS: Test availability for dup3() and pipe2() to prevent crashes when building against Xcode 27

1 participant