@@ -337,6 +337,29 @@ MakeAnonFields(PyObject *type)
337
337
return 0 ;
338
338
}
339
339
340
+ /*
341
+ Allocate a memory block for a pep3118 format string, copy prefix (if
342
+ non-null) into it and append `{padding}x` to the end.
343
+ Returns NULL on failure, with the error indicator set.
344
+ */
345
+ char *
346
+ _ctypes_alloc_format_padding (const char * prefix , Py_ssize_t padding )
347
+ {
348
+ /* int64 decimal characters + x + null */
349
+ char buf [19 + 1 + 1 ];
350
+
351
+ assert (padding > 0 );
352
+
353
+ if (padding == 1 ) {
354
+ /* Use x instead of 1x, for brevity */
355
+ return _ctypes_alloc_format_string (prefix , "x" );
356
+ }
357
+
358
+ int ret = PyOS_snprintf (buf , sizeof (buf ), "%zdx" , padding );
359
+ assert (0 <= ret && ret < sizeof (buf ));
360
+ return _ctypes_alloc_format_string (prefix , buf );
361
+ }
362
+
340
363
/*
341
364
Retrieve the (optional) _pack_ attribute from a type, the _fields_ attribute,
342
365
and create an StgDictObject. Used for Structure and Union subclasses.
@@ -346,11 +369,10 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
346
369
{
347
370
StgDictObject * stgdict , * basedict ;
348
371
Py_ssize_t len , offset , size , align , i ;
349
- Py_ssize_t union_size , total_align ;
372
+ Py_ssize_t union_size , total_align , aligned_size ;
350
373
Py_ssize_t field_size = 0 ;
351
374
int bitofs ;
352
375
PyObject * tmp ;
353
- int isPacked ;
354
376
int pack ;
355
377
Py_ssize_t ffi_ofs ;
356
378
int big_endian ;
@@ -374,7 +396,6 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
374
396
return -1 ;
375
397
}
376
398
if (tmp ) {
377
- isPacked = 1 ;
378
399
pack = _PyLong_AsInt (tmp );
379
400
Py_DECREF (tmp );
380
401
if (pack < 0 ) {
@@ -389,7 +410,7 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
389
410
}
390
411
}
391
412
else {
392
- isPacked = 0 ;
413
+ /* Setting `_pack_ = 0` amounts to using the default alignment */
393
414
pack = 0 ;
394
415
}
395
416
@@ -470,12 +491,10 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
470
491
}
471
492
472
493
assert (stgdict -> format == NULL );
473
- if (isStruct && ! isPacked ) {
494
+ if (isStruct ) {
474
495
stgdict -> format = _ctypes_alloc_format_string (NULL , "T{" );
475
496
} else {
476
- /* PEP3118 doesn't support union, or packed structures (well,
477
- only standard packing, but we don't support the pep for
478
- that). Use 'B' for bytes. */
497
+ /* PEP3118 doesn't support union. Use 'B' for bytes. */
479
498
stgdict -> format = _ctypes_alloc_format_string (NULL , "B" );
480
499
}
481
500
if (stgdict -> format == NULL )
@@ -543,24 +562,53 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
543
562
} else
544
563
bitsize = 0 ;
545
564
546
- if (isStruct && ! isPacked ) {
565
+ if (isStruct ) {
547
566
const char * fieldfmt = dict -> format ? dict -> format : "B" ;
548
567
const char * fieldname = PyUnicode_AsUTF8 (name );
549
568
char * ptr ;
550
569
Py_ssize_t len ;
551
570
char * buf ;
571
+ Py_ssize_t last_size = size ;
572
+ Py_ssize_t padding ;
552
573
553
574
if (fieldname == NULL )
554
575
{
555
576
Py_DECREF (pair );
556
577
return -1 ;
557
578
}
558
579
580
+ /* construct the field now, as `prop->offset` is `offset` with
581
+ corrected alignment */
582
+ prop = PyCField_FromDesc (desc , i ,
583
+ & field_size , bitsize , & bitofs ,
584
+ & size , & offset , & align ,
585
+ pack , big_endian );
586
+ if (prop == NULL ) {
587
+ Py_DECREF (pair );
588
+ return -1 ;
589
+ }
590
+
591
+ /* number of bytes between the end of the last field and the start
592
+ of this one */
593
+ padding = ((CFieldObject * )prop )-> offset - last_size ;
594
+
595
+ if (padding > 0 ) {
596
+ ptr = stgdict -> format ;
597
+ stgdict -> format = _ctypes_alloc_format_padding (ptr , padding );
598
+ PyMem_Free (ptr );
599
+ if (stgdict -> format == NULL ) {
600
+ Py_DECREF (pair );
601
+ Py_DECREF (prop );
602
+ return -1 ;
603
+ }
604
+ }
605
+
559
606
len = strlen (fieldname ) + strlen (fieldfmt );
560
607
561
608
buf = PyMem_Malloc (len + 2 + 1 );
562
609
if (buf == NULL ) {
563
610
Py_DECREF (pair );
611
+ Py_DECREF (prop );
564
612
PyErr_NoMemory ();
565
613
return -1 ;
566
614
}
@@ -578,15 +626,9 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
578
626
579
627
if (stgdict -> format == NULL ) {
580
628
Py_DECREF (pair );
629
+ Py_DECREF (prop );
581
630
return -1 ;
582
631
}
583
- }
584
-
585
- if (isStruct ) {
586
- prop = PyCField_FromDesc (desc , i ,
587
- & field_size , bitsize , & bitofs ,
588
- & size , & offset , & align ,
589
- pack , big_endian );
590
632
} else /* union */ {
591
633
size = 0 ;
592
634
offset = 0 ;
@@ -595,14 +637,14 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
595
637
& field_size , bitsize , & bitofs ,
596
638
& size , & offset , & align ,
597
639
pack , big_endian );
640
+ if (prop == NULL ) {
641
+ Py_DECREF (pair );
642
+ return -1 ;
643
+ }
598
644
union_size = max (size , union_size );
599
645
}
600
646
total_align = max (align , total_align );
601
647
602
- if (!prop ) {
603
- Py_DECREF (pair );
604
- return -1 ;
605
- }
606
648
if (-1 == PyObject_SetAttr (type , name , prop )) {
607
649
Py_DECREF (prop );
608
650
Py_DECREF (pair );
@@ -612,26 +654,41 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
612
654
Py_DECREF (prop );
613
655
}
614
656
615
- if (isStruct && !isPacked ) {
616
- char * ptr = stgdict -> format ;
657
+ if (!isStruct ) {
658
+ size = union_size ;
659
+ }
660
+
661
+ /* Adjust the size according to the alignment requirements */
662
+ aligned_size = ((size + total_align - 1 ) / total_align ) * total_align ;
663
+
664
+ if (isStruct ) {
665
+ char * ptr ;
666
+ Py_ssize_t padding ;
667
+
668
+ /* Pad up to the full size of the struct */
669
+ padding = aligned_size - size ;
670
+ if (padding > 0 ) {
671
+ ptr = stgdict -> format ;
672
+ stgdict -> format = _ctypes_alloc_format_padding (ptr , padding );
673
+ PyMem_Free (ptr );
674
+ if (stgdict -> format == NULL ) {
675
+ return -1 ;
676
+ }
677
+ }
678
+
679
+ ptr = stgdict -> format ;
617
680
stgdict -> format = _ctypes_alloc_format_string (stgdict -> format , "}" );
618
681
PyMem_Free (ptr );
619
682
if (stgdict -> format == NULL )
620
683
return -1 ;
621
684
}
622
685
623
- if (!isStruct )
624
- size = union_size ;
625
-
626
- /* Adjust the size according to the alignment requirements */
627
- size = ((size + total_align - 1 ) / total_align ) * total_align ;
628
-
629
686
stgdict -> ffi_type_pointer .alignment = Py_SAFE_DOWNCAST (total_align ,
630
687
Py_ssize_t ,
631
688
unsigned short );
632
- stgdict -> ffi_type_pointer .size = size ;
689
+ stgdict -> ffi_type_pointer .size = aligned_size ;
633
690
634
- stgdict -> size = size ;
691
+ stgdict -> size = aligned_size ;
635
692
stgdict -> align = total_align ;
636
693
stgdict -> length = len ; /* ADD ffi_ofs? */
637
694
0 commit comments