GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-156933: Widen narrow integer results in ctypes callbacks by lazerg · Pull Request #157045 · python/cpython

Conversation

@lazerg

@lazerg lazerg commented Sep 6, 2026 •
edited by bedevere-app Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

_CallPythonObject() only wrote restype->size bytes into the closure's result buffer, leaving the unused high-order bits of the ffi_arg-sized register untouched. libffi's ffi_prep_closure_loc() documents that integral types narrower than a machine register must be widened to fill it, sign-extending signed types. On architectures that always read the full register for narrow return values (s390x), this leaves garbage in the high bits, which broke libclang callbacks used by cindex.py.

The fix widens narrow integer results into a register-sized buffer before writing them back, sign- or zero-extending depending on the type, replacing the old big-endian-only pointer offset that didn't actually widen anything.

Fixes #156933.

  • Issue: _ctypes fails to extend the return value per libffi contract #156933

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@lazerg
pythongh-156933: Widen narrow integer results in ctypes callbacks
72a218b
@python-cla-bot

python-cla-bot Bot commented Sep 6, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot mentioned this pull request Sep 6, 2026
_ctypes fails to extend the return value per libffi contract #156933
Closed
@bedevere-app bedevere-app Bot added the awaiting review label Sep 6, 2026
@lazerg

lazerg commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

This failure is a 10 minute timeout in test_subprocess's test_check on the macOS Intel runner, unrelated to this change (which only touches _ctypes/callbacks.c).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@hugovk

This comment was marked as resolved.

Sign in to view
ZeroIntensity
ZeroIntensity reviewed Sep 19, 2026
View reviewed changes

@ZeroIntensity ZeroIntensity left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

This needs a test case.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@lazerg

lazerg commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

I couldn't write a test that fails before this fix and passes after it on any CI architecture. The existing test_byte/test_short/test_int callback tests in test_callbacks.py already round-trip narrow return values through a real closure call, and they pass with or without this patch on x86-64 and arm64 — those backends already read back only the bytes they need, so the missing widening never surfaces there. The corruption only shows up on an ABI where the caller trusts the full register width, which in this report is s390x, not one of the PR-gating runners, and I don't have that hardware to verify against. I'm glad to add a value-check test for the narrow int types as basic coverage if you'd still like one, though it won't reproduce the bug itself on x86-64/arm64.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ZeroIntensity

ZeroIntensity commented Sep 20, 2026

Copy link
Copy Markdown
Member

I'm confused; how did you ensure that your fix works if you can't test on s390x? This feels a lot like you fed an issue into Codex/Claude/whatever, and you just sent the PR to us. Please don't try to fix issues that you can't even reproduce.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ZeroIntensity ZeroIntensity added the pending The issue will be closed if no feedback is provided label Sep 20, 2026
@lazerg

lazerg commented Sep 20, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

It was AI-assisted, yes. I reviewed and drove the actual fix, and I get why the s390x question is fair.

Here's what I actually checked: the widening logic follows libffi's own contract for ffi_prep_closure_loc — narrow integer types have to fill a full ffi_arg-sized register, sign- or zero-extended. The old code just shifted a pointer for big-endian and never actually widened anything. I ran the full test_ctypes suite (628 tests) before and after on arm64, no regressions, and I also tried to reproduce the bug directly through register-priming plus a reinterpreted function pointer — it doesn't reproduce on arm64 or x86-64, because those libffi backends only read back the bytes they actually need. That's also why no portable regression test is possible on any architecture CI runs; s390x is the only one that trusts the full register.

If someone with s390x access can confirm the fix before/after, that's better evidence than anything I can produce here — happy to wait on that if you'd rather not merge on the reasoning alone.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Endilll

Endilll commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

@miladfarca can you help testing this fix or find someone with the access to a s390x machine?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ZeroIntensity

ZeroIntensity commented Sep 20, 2026

Copy link
Copy Markdown
Member

I really don't appreciate you copy-pasting AI output as a response. Please use your own words.

I'm going to refrain from reviewing this until someone (preferably from the LLVM team) can confirm that this is the right solution for s390x. I don't completely understand this fix, and given that you can't even reproduce the bug locally, I'm not so sure that you do either.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@miladfarca

miladfarca commented Sep 25, 2026

Copy link
Copy Markdown

I have created this small test case to test this PR, it fails without the patch and passes with it on s390x, I cannot run the entire test suite as I don't have the proper environment:

diff --git a/Lib/test/test_ctypes/test_callbacks.py b/Lib/test/test_ctypes/test_callbacks.py
index 6c7c2e52707..204eb6da301 100644
--- a/Lib/test/test_ctypes/test_callbacks.py
+++ b/Lib/test/test_ctypes/test_callbacks.py
@@ -328,6 +328,14 @@ def func():
                              f"of ctypes callback function {func!r}")
             self.assertIsNone(cm.unraisable.object)
 
+    def test_narrow_int_return_widened(self):
+        @CFUNCTYPE(c_int)
+        def cb():
+            return -1
+
+        addr = ctypes.cast(cb, ctypes.c_void_p).value
+        wide = CFUNCTYPE(c_longlong)(addr)
+        self.assertEqual(wide(), -1)
 
 if __name__ == '__main__':
     unittest.main()
ZeroIntensity reacted with heart emoji
All reactions
  • ❤️ 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lazerg
Add test for widened narrow int callback results
ebf7568
@lazerg

lazerg commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for testing this on s390x! I added your test in ebf7568. I put a 64-bit skip on it, because on 32-bit targets a long long return uses two registers and the callback only sets one. Here on arm64 macOS it passes with and without the fix, so s390x is still the only place where it catches the bug.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lazerg
Only run the widening test on s390x
9338911
@lazerg

lazerg commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

I limited the test to s390x in 9338911. It failed on x86-64 CI even with the fix: libffi zero-extends a 32-bit result there, and the x86-64 ABI leaves the upper bits undefined, so reading an int result as long long is not reliable on that platform. On s390x the ABI requires the callee to extend the result, so the test is valid there and the s390x buildbots will run it.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ZeroIntensity ZeroIntensity removed the pending The issue will be closed if no feedback is provided label Sep 27, 2026
ZeroIntensity
ZeroIntensity reviewed Sep 27, 2026
View reviewed changes
Comment thread Misc/NEWS.d/next/Library/2026-09-07-00-21-31.gh-issue-156933.OalCjC.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Modules/_ctypes/callbacks.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Modules/_ctypes/callbacks.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/test/test_ctypes/test_callbacks.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/test/test_ctypes/test_callbacks.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/test/test_ctypes/test_callbacks.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@ZeroIntensity

ZeroIntensity commented Sep 27, 2026

Copy link
Copy Markdown
Member

Thanks @miladfarca for confirming. I think we do have a few s390x buildbots lying around too. I'll try to run them once the review comments are addressed.

@lazerg In the future, please only work on issues that you can actually verify, and please don't use LLM output to reply to comments. I get that AI is good at solving issues like this, but it ultimately just shifts the cognitive effort to the maintainer/reviewer.

miladfarca reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lazerg

lazerg commented Sep 27, 2026

Copy link
Copy Markdown
Contributor Author

Yes, understood.

ZeroIntensity reacted with heart emoji
All reactions
  • ❤️ 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@lazerg
Address review comments
d54ca1f
ZeroIntensity
ZeroIntensity reviewed Sep 27, 2026
View reviewed changes
Comment thread Lib/test/test_ctypes/test_callbacks.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

lazerg and others added 2 commits September 27, 2026 08:26
@lazerg
Use wrap_dll_function in the widening test
6490b5f
@ZeroIntensity
Merge branch 'main' into fix/issue-156933-ctypes-callback-widen
5693c85
@ZeroIntensity

ZeroIntensity commented Sep 27, 2026

Copy link
Copy Markdown
Member

!buildbot s390x

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-bot

bedevere-bot commented Sep 27, 2026

Copy link
Copy Markdown

🤖 New build scheduled with the buildbot fleet by @ZeroIntensity for commit 5693c85 🤖

Results will be shown at:

https://buildbot.python.org/all/#/grid?branch=refs%2Fpull%2F157045%2Fmerge

The command will test the builders whose names match following regular expression: s390x

The builders matched are:

  • s390x CentOS10 Clang Installed PR
  • s390x Fedora Stable LTO PR
  • s390x Fedora Stable Clang Installed PR
  • s390x Fedora Rawhide NoGIL refleaks PR
  • s390x Fedora Stable LTO + PGO PR
  • s390x Fedora Rawhide LTO + PGO PR
  • s390x CentOS10 LTO PR
  • s390x Fedora Rawhide Clang PR
  • s390x RHEL9 LTO PR
  • s390x Fedora Stable PR
  • s390x CentOS10 Clang PR
  • s390x Fedora Rawhide Clang Installed PR
  • s390x RHEL9 PR
  • s390x CentOS10 Refleaks PR
  • s390x RHEL9 LTO + PGO PR
  • s390x CentOS10 PR
  • s390x Fedora Stable Refleaks PR
  • s390x Fedora Rawhide NoGIL PR
  • s390x Fedora Rawhide PR
  • s390x CentOS10 LTO + PGO PR
  • s390x Fedora Rawhide LTO PR
  • s390x Fedora Rawhide Refleaks PR
  • s390x RHEL9 Refleaks PR
  • s390x Fedora Stable Clang PR
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ZeroIntensity ZeroIntensity mentioned this pull request Sep 27, 2026
test_dtrace fails on s390x Fedora buildbots #158294
Closed
@ZeroIntensity ZeroIntensity added the needs backport to 3.13 only security fixes label Sep 27, 2026
@ZeroIntensity ZeroIntensity added needs backport to 3.14 bugs and security fixes needs backport to 3.15 bugs and security fixes labels Sep 27, 2026
ZeroIntensity
ZeroIntensity approved these changes Sep 27, 2026
View reviewed changes

@ZeroIntensity ZeroIntensity left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Thanks, this looks good. The buildbot failures on Fedora look unrelated; I've opened an issue: #158294.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting review labels Sep 27, 2026
@ZeroIntensity
ZeroIntensity merged commit b6f9a50 into python:main Sep 27, 2026
79 of 85 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@miss-islington-app

miss-islington-app Bot commented Sep 27, 2026

Copy link
Copy Markdown

Thanks @lazerg for the PR, and @ZeroIntensity for merging it 🌮🎉.. I'm working now to backport this PR to: 3.13, 3.14, 3.15.
🐍🍒⛏🤖

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the awaiting merge label Sep 27, 2026
@bedevere-app

bedevere-app Bot commented Sep 27, 2026

Copy link
Copy Markdown

GH-158295 is a backport of this pull request to the 3.15 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the needs backport to 3.15 bugs and security fixes label Sep 27, 2026
@miss-islington-app

miss-islington-app Bot commented Sep 27, 2026

Copy link
Copy Markdown

Sorry, @lazerg and @ZeroIntensity, I could not cleanly backport this to 3.13 due to a conflict.
Please backport using cherry_picker on command line.

cherry_picker b6f9a50e654dd76394bece71e6a8240ef28107ab 3.13
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@miss-islington-app miss-islington-app Bot assigned ZeroIntensity Sep 27, 2026
@bedevere-app

bedevere-app Bot commented Sep 27, 2026

Copy link
Copy Markdown

GH-158296 is a backport of this pull request to the 3.14 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the needs backport to 3.14 bugs and security fixes label Sep 27, 2026
@bedevere-app

bedevere-app Bot commented Sep 27, 2026

Copy link
Copy Markdown

GH-158297 is a backport of this pull request to the 3.13 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the needs backport to 3.13 only security fixes label Sep 27, 2026
ZeroIntensity added a commit that referenced this pull request Sep 27, 2026
@ZeroIntensity @lazerg
[3.13] gh-156933: Widen narrow integer results in ctypes callbacks (G…
ca0cdf4
…H-157045) (GH-158297)

_CallPythonObject() only wrote restype->size bytes into the closure's result buffer, leaving the unused high-order bits of the ffi_arg-sized register untouched. libffi's ffi_prep_closure_loc() documents that integral types narrower than a machine register must be widened to fill it, sign-extending signed types. On architectures that always read the full register for narrow return values (s390x), this leaves garbage in the high bits, which broke libclang callbacks used by cindex.py.

(cherry picked from commit b6f9a50)

Co-authored-by: Lazizbek Ergashev <[email protected]>
ZeroIntensity pushed a commit that referenced this pull request Sep 27, 2026
@miss-islington @lazerg
[3.14] gh-156933: Widen narrow integer results in ctypes callbacks (G…
e4e5835
…H-157045) (GH-158296)

_CallPythonObject() only wrote restype->size bytes into the closure's result buffer, leaving the unused high-order bits of the ffi_arg-sized register untouched. libffi's ffi_prep_closure_loc() documents that integral types narrower than a machine register must be widened to fill it, sign-extending signed types. On architectures that always read the full register for narrow return values (s390x), this leaves garbage in the high bits, which broke libclang callbacks used by cindex.py.

(cherry picked from commit b6f9a50)

Co-authored-by: Lazizbek Ergashev <[email protected]>
hugovk pushed a commit that referenced this pull request Sep 28, 2026
@miss-islington @lazerg @ZeroIntensity
[3.15] gh-156933: Widen narrow integer results in ctypes callbacks (G…
cc3ab21
…H-157045) (#158295)

Co-authored-by: Lazizbek Ergashev <[email protected]>
Co-authored-by: Peter Bierma <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@ZeroIntensity ZeroIntensity ZeroIntensity approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

@ZeroIntensity ZeroIntensity

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

_ctypes fails to extend the return value per libffi contract

Uh oh!

There was an error while loading. Please reload this page.

6 participants

@lazerg @hugovk @ZeroIntensity @Endilll @miladfarca @bedevere-bot
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.