-
-
Notifications
You must be signed in to change notification settings - Fork 34.5k
gh-97588: Fix ctypes structs #97702
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
gh-97588: Fix ctypes structs #97702
Changes from 1 commit
7922585
2307932
47f826c
5a32211
8d79d8f
2d07375
8bc8535
c3d162b
e5ed9ac
b0f9819
2dee0e3
79ef347
6170dad
871ca1a
c162144
a57cf2c
3f7c4cc
e39a271
359ed58
52ef8d2
e8102c4
600e144
9bad706
5121857
6cd27ea
6b6fa8a
ca9d580
1401ee4
235fa68
a534e18
53db061
9c249c3
3cf4747
8beddb9
9b64ff6
4d0dab5
bf98667
8223063
e80a09a
33a10fb
0f3c5a3
47eca3c
456afd0
bc799ac
212cf13
e7e5ae9
45e26ec
ab42187
640c062
f3e04af
bff34a1
5d6f0f7
d9c1fca
cc9ea8a
1554083
a86eadc
eefa1ad
28c7fe7
f0a92b0
a3a390b
e997b5f
5a7ea09
0f73919
cdfc3c6
6226e55
4d48eba
20b5582
eb502d7
0cf5f4e
3457558
fd3cd0b
2d8492e
a9f7f14
bee6c53
220e19e
60cebe2
3424a7d
2506eea
65654b4
98767da
3ca703f
c40ef7d
d840f01
8b9f0eb
4e8c220
0369d0d
d4dc2c0
f75d7d6
cdc5cdc
0da36ad
b6f7117
5e47d5f
de22b39
cdd1860
dd84ac3
8a6fb67
07ea42d
3fa7f55
eb2c4fb
22cd86c
637b961
5309b7e
489c5c8
3594473
f780496
6ade022
cfa6647
df162b0
836a5cc
b07ae33
6dd7a8d
0cf1049
bc91549
70bbc26
6e23b3d
1b90841
2c4874b
738323f
af7487c
5353352
fe76d45
c4714f1
c79725d
cace0c9
61e92bf
ba61051
8991444
bc1225b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
…ield-clean
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -89,7 +89,7 @@ PyCField_FromDesc manages: | |
| static void | ||
| PyCField_FromDesc_gcc(Py_ssize_t bitsize, Py_ssize_t *pbitofs, | ||
| Py_ssize_t *psize, Py_ssize_t *poffset, Py_ssize_t *palign, | ||
| CFieldObject* self, StgDictObject* dict, | ||
| CFieldObject* self, StgInfo* dict, | ||
| int is_bitfield | ||
| ) | ||
| { | ||
|
|
@@ -127,7 +127,7 @@ PyCField_FromDesc_msvc( | |
| Py_ssize_t *pfield_size, Py_ssize_t bitsize, | ||
| Py_ssize_t *pbitofs, Py_ssize_t *psize, Py_ssize_t *poffset, | ||
| Py_ssize_t *palign, int pack, | ||
| CFieldObject* self, StgDictObject* dict, | ||
| CFieldObject* self, StgInfo* dict, | ||
| int is_bitfield | ||
| ) | ||
| { | ||
|
|
@@ -182,8 +182,15 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index, | |
| CFieldObject* self = (CFieldObject *)tp->tp_alloc(tp, 0); | ||
| if (self == NULL) | ||
| return NULL; | ||
| StgDictObject* dict = PyType_stgdict(desc); | ||
| if (!dict) { | ||
| // Note(Matthias): We get most of what used to be `dict` out of `info` now. | ||
| // StgDictObject* dict = PyType_stgdict(desc); | ||
| // if (!dict) { | ||
| StgInfo *info; | ||
| if (PyStgInfo_FromType(st, desc, &info) < 0) { | ||
| Py_DECREF(self); | ||
| return NULL; | ||
| } | ||
| if (!info) { | ||
| PyErr_SetString(PyExc_TypeError, | ||
| "has no _stginfo_"); | ||
| Py_DECREF(self); | ||
|
|
@@ -237,35 +244,35 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index, | |
|
|
||
| int is_bitfield = !!bitsize; | ||
| if(!is_bitfield) { | ||
| assert(dict->size >= 0); | ||
| assert(info->size >= 0); | ||
| // assert: no overflow; | ||
| assert((unsigned long long int) dict->size | ||
| assert((unsigned long long int) info->size | ||
| < (1ULL << (8*sizeof(Py_ssize_t)-1)) / 8); | ||
| bitsize = 8 * dict->size; | ||
| bitsize = 8 * info->size; | ||
| // Caution: bitsize might still be 0 now. | ||
| } | ||
| assert(bitsize <= dict->size * 8); | ||
| assert(bitsize <= info->size * 8); | ||
|
|
||
| // `pack` only makes sense in msvc compatibility mode. | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://docs.python.org/3/library/ctypes.html#structure-union-alignment-and-byte-order says
GCC has a suspiciously similarly named
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: the behaviour described in the quoted docs that we are implementing here is rather different from what everyone in #19850 seems to have understood. As far as I can tell in that PR everyone assume that This misunderstanding might be an argument for changing the docs? However that would be a breaking change. In general, this PR breaks bug-for-bug compatibility with the past, but does not change documented behaviour. At the moment, we don't support GCC's version of packed structs. Neither in the existing code nor in this PR. It's fairly easy to add this behaviour on top of my code; but I would suggest using a new attribute (like
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correction: support for GCC's packing isn't actually as easy as I imagined. The problem is that GCC's packing can make eg a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here's an example to show the problem: #include <stdio.h>
#include <stdint.h>
#include <string.h>
typedef struct
__attribute__ ((packed))
{
uint8_t a: 4;
uint8_t b: 8;
uint8_t c: 4;
} Foo;
typedef union {
Foo foo;
uint8_t x[sizeof(Foo)];
} U;
int main(int argc, char** argv) {
printf("%lu\n", __alignof__(Foo));
printf("%lu\n", sizeof(Foo));
U u;
memset(&u, 0, sizeof(U));
// Set b to all 1s.
u.foo.b = -1;
// Because we are on a little endian machine, it makes more sense to print
// the bytes in reverse order.
// This prints "0f f0", showing that b straddles a byte.
for(int i=sizeof(Foo)-1; i>=0; --i) {
printf("%02x ", u.x[i]);
}
printf("\n");
return 0;
}
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess the right thing to do here would be to warn when |
||
| if (ms_struct || pack != 0) { | ||
| PyCField_FromDesc_msvc( | ||
| pfield_size, bitsize, pbitofs, | ||
| psize, poffset, palign, | ||
| pack, | ||
| self, dict, | ||
| self, info, | ||
| is_bitfield | ||
| ); | ||
| } else { | ||
| PyCField_FromDesc_gcc( | ||
| bitsize, pbitofs, | ||
| psize, poffset, palign, | ||
| self, dict, | ||
| self, info, | ||
| is_bitfield | ||
| ); | ||
| } | ||
| assert(!is_bitfield || (LOW_BIT(self->size) <= self->size * 8)); | ||
| if(big_endian && is_bitfield) { | ||
| self->size = BUILD_SIZE(NUM_BITS(self->size), 8*dict->size - LOW_BIT(self->size) - bitsize); | ||
| self->size = BUILD_SIZE(NUM_BITS(self->size), 8*info->size - LOW_BIT(self->size) - bitsize); | ||
| } | ||
| return (PyObject *)self; | ||
| } | ||
|
|
||
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.
When I changed StgDict to StgInfo, it took several commits (and false attempts); to keep it all straight I renamed
dictvariables toinfo.I recommend doing it too, so the names aren't misleading.
Sorry for the extra work :(
(For the record: When there's a need to access
__dict__(attributes of the Python object), I called the new variableattrdict. Nowadays, after the transition,dictis OK for that.)