As a hopefully helpful cleanup task, I went through all the uses of __wasi__ special-casing in the CPython code and tried to figure out if any of them were not necessary anymore, mostly looking at the ones that might have been fixed by changes in wasi-libc.
I found a few, but the rest look like they are still needed. Happy to send PRs for the couple of ones at the top of the list which look like they can be safely removed.
The rest of the list is probably not useful, but I figured I would include it for completeness in case I have made some incorrect assumptions that stand out.
Full disclosure: I started off going through these one by one myself, but after the first pass to understand the patterns, I used Claude to scan and categorise the usages and to cross reference the wasi-libc changes where relevant. I did review the results carefully myself - especially spending time on the ones that looked like possible candidates for removal and doing my own searches for relevant issues/discussions. I've included some of the AI-generated summary, but I cut it down a lot and reworded it myself.
Good candidates for removal:
Modules/selectmodule.c:76 — define POLLPRI as no-op 0; missing from WASI SDK 16.
This is now defined in __header_poll.h as 0x0200 as of WASI SDK 33. It was added by wasi-libc PR #754 (merged); design discussion in issue #760 (open).
Modules/socketmodule.c:8428 — define the recv-truncated flag to work around wasi-libc issue #305, so MSG_TRUNC can be exported.
Looks like this was fixed by wasi-libc PR #391 (merged 2023-02-04); tracking issue #305 is still marked open but I think it could be closed now.
Possible candiates for removal:
linkat (posixmodule.c:4877) - This one needs further investigation or context it's not super clear to me why WASI was special-cased here.
Introduced by gh-81793 / PR #132517 (May 2025) which doesn't explicitly mention why the __wasi__ check was added. Possibly to preserve WASI's prior behaviour rather than risk changing the behavior, but it could be fine to remove. Removing it changes os.link's default symlink handling, so it could depend on what the WASi implementation does with that, I haven't tested removing this.
Could possibly be removed for preview2/3 when dropping support for preview1:
Parser/tokenizer/reader.c:718 — use a "borrowed fd" instead of dup().
wasi-libc implemented the dup-family for WASIp2/WASIp3 in PR #832 and PR #822, but the workaround must stay for preview1 (issue #459).
Probably need to be kept:
Modules/posixmodule.c:4157 — os.chmod becomes a no-op because WASI has no chmod or the underlying permission model.
wasi-libc added stubs in PR #463 that return ENOSYS, but CPython used these, it would cause a bunch of operations to error (same for relying on HAVE_CHMOD). The default of success is not great either (attempting to restrict permissions silently doesn't work), but it would need quite a bit of work to resolve all the cases where changing this would break something.
Modules/posixmodule.c:13549 and Modules/clinic/posixmodule.c.h:9534 — posix_fallocate was dropped in WASI preview2 due to inconsistent cross-OS semantics.
Python/fileutils.c:3145 — exclude WASI from the fast fcntl(F_GETFD) fd-validity path.
wasi-libc handles fcntl(F_GETFD), but it returns FD_CLOEXEC unconditionally without validating the fd, so it can't detect a bad fd. It's correct to fall back to fstat() for _Py_fd_is_valid.
Modules/_testinternalcapi.c:47, :241 — skip <dlfcn.h>/dladdr address classification.
wasi-libc has dlopen/dlsym stubs (PR #443) and shared-library build support (PR #429), but dladdr is still absent and there's no full runtime dynamic linking.
Modules/errnomodule.c:295 — alias ESHUTDOWN to EPIPE; missing from WASI SDK 16.
Looks like it's still needed. A WASI build uses __errno_values.h (EPIPE 64, no ESHUTDOWN), not musl's generic bits/errno.h. WASI preview1 has no such errno.
Special cases for WASM Stack size
I'm not super clear on the reasons for the smaller stack size limits. I suspect it's related to the 16MiB stack size specified here:
|
AS_VAR_APPEND([LDFLAGS_NODIST], [" -z stack-size=16777216 -Wl,--stack-first -Wl,--initial-memory=41943040"]) |
(side note
--stack-first is apparently the default now, so perhaps in future that can be removed).
I suspect these ones need to stay.
Threading stuff
I didn't go as deep on the threading cases, but as far as I can tell all of these need to stay. There's still no pause() and pthread_exit or pthread_cleanup_push etc. Though there is a discussion on adding pthread_exit to WASI.
Unavailable features
Also didn't look closely at these ones, but I suspect they need to stay - I don't see the semantics of the cpu time clocks changing in WASI any time soon, also I'm not clear on what it would take to implement subinterpreters.
Vendored third-party code
Changes to these should be considered upstream.
Objects/mimalloc/** and Include/internal/mimalloc/** — mimalloc's own WASI port.
Modules/expat/xmlparse.c — vendored Expat's own WASI handling.
As a hopefully helpful cleanup task, I went through all the uses of
__wasi__special-casing in the CPython code and tried to figure out if any of them were not necessary anymore, mostly looking at the ones that might have been fixed by changes inwasi-libc.I found a few, but the rest look like they are still needed. Happy to send PRs for the couple of ones at the top of the list which look like they can be safely removed.
The rest of the list is probably not useful, but I figured I would include it for completeness in case I have made some incorrect assumptions that stand out.
Full disclosure: I started off going through these one by one myself, but after the first pass to understand the patterns, I used Claude to scan and categorise the usages and to cross reference the
wasi-libcchanges where relevant. I did review the results carefully myself - especially spending time on the ones that looked like possible candidates for removal and doing my own searches for relevant issues/discussions. I've included some of the AI-generated summary, but I cut it down a lot and reworded it myself.Good candidates for removal:
Modules/selectmodule.c:76— definePOLLPRIas no-op0; missing from WASI SDK 16.This is now defined in
__header_poll.has0x0200as of WASI SDK 33. It was added by wasi-libc PR #754 (merged); design discussion in issue #760 (open).Modules/socketmodule.c:8428— define the recv-truncated flag to work aroundwasi-libcissue #305, soMSG_TRUNCcan be exported.Looks like this was fixed by wasi-libc PR #391 (merged 2023-02-04); tracking issue #305 is still marked open but I think it could be closed now.
Possible candiates for removal:
linkat(posixmodule.c:4877) - This one needs further investigation or context it's not super clear to me why WASI was special-cased here.Introduced by gh-81793 / PR #132517 (May 2025) which doesn't explicitly mention why the
__wasi__check was added. Possibly to preserve WASI's prior behaviour rather than risk changing the behavior, but it could be fine to remove. Removing it changesos.link's default symlink handling, so it could depend on what the WASi implementation does with that, I haven't tested removing this.Could possibly be removed for preview2/3 when dropping support for preview1:
Parser/tokenizer/reader.c:718— use a "borrowed fd" instead ofdup().wasi-libc implemented the
dup-family for WASIp2/WASIp3 in PR #832 and PR #822, but the workaround must stay for preview1 (issue #459).Probably need to be kept:
Modules/posixmodule.c:4157—os.chmodbecomes a no-op because WASI has nochmodor the underlying permission model.wasi-libc added stubs in PR #463 that return
ENOSYS, but CPython used these, it would cause a bunch of operations to error (same for relying onHAVE_CHMOD). The default of success is not great either (attempting to restrict permissions silently doesn't work), but it would need quite a bit of work to resolve all the cases where changing this would break something.Modules/posixmodule.c:13549andModules/clinic/posixmodule.c.h:9534—posix_fallocatewas dropped in WASI preview2 due to inconsistent cross-OS semantics.Python/fileutils.c:3145— exclude WASI from the fastfcntl(F_GETFD)fd-validity path.wasi-libc handles
fcntl(F_GETFD), but it returnsFD_CLOEXECunconditionally without validating the fd, so it can't detect a bad fd. It's correct to fall back tofstat()for_Py_fd_is_valid.Modules/_testinternalcapi.c:47,:241— skip<dlfcn.h>/dladdraddress classification.wasi-libc has
dlopen/dlsymstubs (PR #443) and shared-library build support (PR #429), butdladdris still absent and there's no full runtime dynamic linking.Modules/errnomodule.c:295— aliasESHUTDOWNtoEPIPE; missing from WASI SDK 16.Looks like it's still needed. A WASI build uses
__errno_values.h(EPIPE 64, noESHUTDOWN), not musl's genericbits/errno.h. WASI preview1 has no such errno.Special cases for WASM Stack size
I'm not super clear on the reasons for the smaller stack size limits. I suspect it's related to the 16MiB stack size specified here:
cpython/configure.ac
Line 2500 in 41b3f0a
--stack-firstis apparently the default now, so perhaps in future that can be removed).I suspect these ones need to stay.
Parser/parser.c:11— lowerMAXSTACKTools/peg_generator/pegen/c_generator.py:42— the template that generates theparser.ccap above.Python/marshal.c:47— reducedMAX_MARSHAL_STACK_DEPTHThreading stuff
I didn't go as deep on the threading cases, but as far as I can tell all of these need to stay. There's still no
pause()andpthread_exitorpthread_cleanup_pushetc. Though there is a discussion on addingpthread_exitto WASI.Include/pyport.h:478— leavePy_CAN_START_THREADSundefined; non-threaded WASI has no threads.Include/cpython/pthread_stubs.h:21— coaxpthread_*type declarations out ofbits/alltypes.hvia__NEED_*macros when threads are stubbed.Python/thread_pthread.h:421—abort()instead ofpthread_exit, whichwasi-threadslacks. Tracked upstream by wasi-threads#7 ("Iswasi_thread_exitneeded?"), still open (created Oct 2022)Python/thread_pthread.h:436—sleep(9999999)instead ofpause(), whichwasi-libclacks.Modules/_testcapimodule.c:2448,:2463,:2469— nopthread_cleanup_push/popUnavailable features
Also didn't look closely at these ones, but I suspect they need to stay - I don't see the semantics of the cpu time clocks changing in WASI any time soon, also I'm not clear on what it would take to implement subinterpreters.
Modules/timemodule.c:80,:1272,:1411,:2146— don't usetimes()on WASI; no meaningful process CPU accounting (On WASI, time.process_time is not in seconds #115714).Modules/timemodule.c:1347— disable process-CPU-time viaCLOCK_PROCESS_CPUTIME_ID.Modules/timemodule.c:1549— disable thread-CPU-time viaCLOCK_THREAD_CPUTIME_ID.Python/sysmodule.c:3765— reportsupports_isolated_interpreters = False; PEP-734 subinterpreters aren't enabled on WASM builds yet.Vendored third-party code
Changes to these should be considered upstream.
Objects/mimalloc/**andInclude/internal/mimalloc/**— mimalloc's own WASI port.Modules/expat/xmlparse.c— vendored Expat's own WASI handling.