-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ctypes: memoryview gives incorrect PEP3118 format strings for both packed and unpacked structs #76961
Comments
Discovered here Consider the following structure, and a memoryview created from it: class foo(ctypes.Structure):
_fields_ = [('one', ctypes.c_uint8),
('two', ctypes.c_uint32)]
f = foo()
mf = memoryview(f) We'd expect this to insert padding, and it does: >>> mf.itemsize
8 But that padding doesn't show up in the format string: >>> mf.format
'T{<B:one:<I:two:}' That format string describes the packed version of the struct, with the
But ctypes doesn't even get it right for packed structs: class foop(ctypes.Structure):
_fields_ = [('one', ctypes.c_uint8),
('two', ctypes.c_uint32)]
_pack_ = 1
f = foo()
mf = memoryview(f) The size is what we'd expect: >>> mf.itemsize
5 But the format is garbage: >>> mf.format
'B' # sizeof(byte) == 5!? |
Pinging, as recommended by https://devguide.python.org/pullrequest/#reviewing. PEP-3118 as a protocol is far less useful if the canonical implementation is non-compliant. |
Unfortunately, the PEP authors did very little in terms of implementing the PEP and neither CPython nor numpy has a fully compliant implementation. |
I guess I'll weigh in since I was pinged. I agree with the approach in the patch. All the memoryview does is to use the format field verbatim from the underlying buffer, so if the format field is inaccurate then the only thing to do is to fix the object providing the buffer. Since the format field is only there for interpretation of the data, and is not used to calculate of itemsizes or strides anywhere as far as I know, it's a fairly low-risk change. However, the patch still leaves ctypes inaccurate for the case of unions. It should be fairly simple to modify the code to use a format of "B<size>" for unions, so that it at least matches the itemsize, even if the type information is lost. (As an aside, let me point out that I did not actually write or advocate for the PEP; for some reason my name was added to it even though I all I did was to provide feedback.) |
Seems reasonable, although:
|
Fixing one case is better than fixing no cases. |
Since Terry added me: Yes, this is clearly a bug, but it is a ctypes issue and not a memoryview issue. ctypes issues unfortunately tend to take some time until someone reviews. |
Is there a ctypes or PEP-3118 core-dev who could review the issue and the PR solution? |
I don't think I'm especially qualified to review this, unfortunately. I did work on some |
Thanks for the response. Do you have any specific committers in mind? I guess I could ping Travis, the other PEP author; but what #5561 needs is a review from someone with commit bit. |
Sadly, |
Yes, I've noticed that too. PEP3118 expertise seems even more sparse, with my impression being that numpy developers are more familiar with it that CPython ones (#5561 is both submitted and approved by a numpy maintainer). Is there anything I could do to this issue or PR to make it more accessible to reviewers who are familiar with the C code but not with ctypes?
My claim is that this particular fix shouldn't change any architecture-specific behavior; the logic for laying out the ctypes fields in memory hasn't changed; all that's changed is the PEP3118 reporting of the layout that was used. |
Sure. I was only giving my perceived reason as to why core developers don't have familiarity with |
@eric-wieser - it looks like I dropped the ball on this quite some time ago. I will see it through this time. Feel free to bug me here if I don't. :) |
@abalkin 🐛 |
The summary of this diff is that it: * adds a `_ctypes_alloc_format_padding` function to append strings like `37x` to a format string to indicate 37 padding bytes * removes the branches that amount to "give up on producing a valid format string if the struct is packed" * combines the resulting adjacent `if (isStruct) {`s now that neither is `if (isStruct && !isPacked) {` * invokes `_ctypes_alloc_format_padding` to add padding between structure fields, and after the last structure field. The computation used for the total size is unchanged from ctypes already used. This patch does not affect any existing aligment computation; all it does is use subtraction to deduce the amount of paddnig introduced by the existing code. --- Without this fix, it would never include padding bytes - an assumption that was only valid in the case when `_pack_` was set - and this case was explicitly not implemented. This should allow conversion from ctypes structs to numpy structs Fixes numpy/numpy#10528
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
Linked PRs
The text was updated successfully, but these errors were encountered: