@@ -328,6 +328,48 @@ MakeAnonFields(PyObject *type)
328
328
return 0 ;
329
329
}
330
330
331
+ /*
332
+ Compute ceil(log10(x)), for the purpose of determining string lengths.
333
+ */
334
+ static Py_ssize_t
335
+ clog10 (Py_ssize_t n )
336
+ {
337
+ Py_ssize_t log_n = 0 ;
338
+ while (n > 0 ) {
339
+ log_n ++ ;
340
+ n /= 10 ;
341
+ }
342
+ return log_n ;
343
+ }
344
+
345
+ /*
346
+ Append {padding}x to the PEP3118 format string.
347
+ */
348
+ char *
349
+ _ctypes_alloc_format_padding (const char * prefix , Py_ssize_t padding )
350
+ {
351
+ char * result ;
352
+ char * buf ;
353
+
354
+ assert (padding > 0 );
355
+
356
+ if (padding == 1 ) {
357
+ /* Use x instead of 1x, for brevity */
358
+ return _ctypes_alloc_format_string (prefix , "x" );
359
+ }
360
+
361
+ /* decimal characters + x + null */
362
+ buf = PyMem_Malloc (clog10 (padding ) + 2 );
363
+ if (buf == NULL ) {
364
+ PyErr_NoMemory ();
365
+ return NULL ;
366
+ }
367
+ sprintf (buf , "%zdx" , padding );
368
+ result = _ctypes_alloc_format_string (prefix , buf );
369
+ PyMem_Free (buf );
370
+ return result ;
371
+ }
372
+
331
373
/*
332
374
Retrieve the (optional) _pack_ attribute from a type, the _fields_ attribute,
333
375
and create an StgDictObject. Used for Structure and Union subclasses.
@@ -337,7 +379,7 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
337
379
{
338
380
StgDictObject * stgdict , * basedict ;
339
381
Py_ssize_t len , offset , size , align , i ;
340
- Py_ssize_t union_size , total_align ;
382
+ Py_ssize_t union_size , total_align , aligned_size ;
341
383
Py_ssize_t field_size = 0 ;
342
384
int bitofs ;
343
385
PyObject * isPacked ;
@@ -443,12 +485,10 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
443
485
}
444
486
445
487
assert (stgdict -> format == NULL );
446
- if (isStruct && ! isPacked ) {
488
+ if (isStruct ) {
447
489
stgdict -> format = _ctypes_alloc_format_string (NULL , "T{" );
448
490
} else {
449
- /* PEP3118 doesn't support union, or packed structures (well,
450
- only standard packing, but we don't support the pep for
451
- that). Use 'B' for bytes. */
491
+ /* PEP3118 doesn't support union. Use 'B' for bytes. */
452
492
stgdict -> format = _ctypes_alloc_format_string (NULL , "B" );
453
493
}
454
494
if (stgdict -> format == NULL )
@@ -515,24 +555,51 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
515
555
} else
516
556
bitsize = 0 ;
517
557
518
- if (isStruct && ! isPacked ) {
558
+ if (isStruct ) {
519
559
const char * fieldfmt = dict -> format ? dict -> format : "B" ;
520
560
const char * fieldname = PyUnicode_AsUTF8 (name );
521
561
char * ptr ;
522
562
Py_ssize_t len ;
523
563
char * buf ;
564
+ Py_ssize_t last_size = size ;
565
+ Py_ssize_t padding ;
524
566
525
567
if (fieldname == NULL )
526
568
{
527
569
Py_DECREF (pair );
528
570
return -1 ;
529
571
}
530
572
573
+ prop = PyCField_FromDesc (desc , i ,
574
+ & field_size , bitsize , & bitofs ,
575
+ & size , & offset , & align ,
576
+ pack , big_endian );
577
+ if (prop == NULL ) {
578
+ Py_DECREF (pair );
579
+ return -1 ;
580
+ }
581
+
582
+ /* number of bytes between the end of the last field and the start
583
+ of this one */
584
+ padding = ((CFieldObject * )prop )-> offset - last_size ;
585
+
586
+ if (padding > 0 ) {
587
+ ptr = stgdict -> format ;
588
+ stgdict -> format = _ctypes_alloc_format_padding (ptr , padding );
589
+ PyMem_Free (ptr );
590
+ if (stgdict -> format == NULL ) {
591
+ Py_DECREF (pair );
592
+ Py_DECREF (prop );
593
+ return -1 ;
594
+ }
595
+ }
596
+
531
597
len = strlen (fieldname ) + strlen (fieldfmt );
532
598
533
599
buf = PyMem_Malloc (len + 2 + 1 );
534
600
if (buf == NULL ) {
535
601
Py_DECREF (pair );
602
+ Py_DECREF (prop );
536
603
PyErr_NoMemory ();
537
604
return -1 ;
538
605
}
@@ -550,15 +617,9 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
550
617
551
618
if (stgdict -> format == NULL ) {
552
619
Py_DECREF (pair );
620
+ Py_DECREF (prop );
553
621
return -1 ;
554
622
}
555
- }
556
-
557
- if (isStruct ) {
558
- prop = PyCField_FromDesc (desc , i ,
559
- & field_size , bitsize , & bitofs ,
560
- & size , & offset , & align ,
561
- pack , big_endian );
562
623
} else /* union */ {
563
624
size = 0 ;
564
625
offset = 0 ;
@@ -567,14 +628,14 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
567
628
& field_size , bitsize , & bitofs ,
568
629
& size , & offset , & align ,
569
630
pack , big_endian );
631
+ if (prop == NULL ) {
632
+ Py_DECREF (pair );
633
+ return -1 ;
634
+ }
570
635
union_size = max (size , union_size );
571
636
}
572
637
total_align = max (align , total_align );
573
638
574
- if (!prop ) {
575
- Py_DECREF (pair );
576
- return -1 ;
577
- }
578
639
if (-1 == PyObject_SetAttr (type , name , prop )) {
579
640
Py_DECREF (prop );
580
641
Py_DECREF (pair );
@@ -585,29 +646,45 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct
585
646
}
586
647
#undef realdict
587
648
588
- if (isStruct && !isPacked ) {
589
- char * ptr = stgdict -> format ;
649
+ if (!isStruct ) {
650
+ size = union_size ;
651
+ }
652
+
653
+ /* Adjust the size according to the alignment requirements */
654
+ aligned_size = ((size + total_align - 1 ) / total_align ) * total_align ;
655
+
656
+ if (isStruct ) {
657
+ char * ptr ;
658
+ Py_ssize_t padding ;
659
+
660
+ /* Pad up to the full size of the struct */
661
+ padding = aligned_size - size ;
662
+ if (padding > 0 ) {
663
+ ptr = stgdict -> format ;
664
+ stgdict -> format = _ctypes_alloc_format_padding (ptr , padding );
665
+ PyMem_Free (ptr );
666
+ if (stgdict -> format == NULL ) {
667
+ return -1 ;
668
+ }
669
+ }
670
+
671
+ ptr = stgdict -> format ;
590
672
stgdict -> format = _ctypes_alloc_format_string (stgdict -> format , "}" );
591
673
PyMem_Free (ptr );
592
674
if (stgdict -> format == NULL )
593
675
return -1 ;
594
676
}
595
677
596
- if (!isStruct )
597
- size = union_size ;
598
-
599
- /* Adjust the size according to the alignment requirements */
600
- size = ((size + total_align - 1 ) / total_align ) * total_align ;
601
-
602
678
stgdict -> ffi_type_pointer .alignment = Py_SAFE_DOWNCAST (total_align ,
603
679
Py_ssize_t ,
604
680
unsigned short );
605
- stgdict -> ffi_type_pointer .size = size ;
681
+ stgdict -> ffi_type_pointer .size = aligned_size ;
606
682
607
- stgdict -> size = size ;
683
+ stgdict -> size = aligned_size ;
608
684
stgdict -> align = total_align ;
609
685
stgdict -> length = len ; /* ADD ffi_ofs? */
610
686
687
+
611
688
/* We did check that this flag was NOT set above, it must not
612
689
have been set until now. */
613
690
if (stgdict -> flags & DICTFLAG_FINAL ) {
0 commit comments