[2.7] bpo-34603, ctypes/libffi_msvc: Fix returning structs from funct… · python/cpython@b63a16f (original) (raw)

7 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -52,6 +52,24 @@ def test_noargs(self):
52 52 # This is a special case on win32 x64
53 53 windll.user32.GetDesktopWindow()
54 54
55 +@unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
56 +class ReturnStructSizesTestCase(unittest.TestCase):
57 +def test_sizes(self):
58 +dll = CDLL(_ctypes_test.__file__)
59 +for i in range(1, 11):
60 +fields = [ ("f%d" % f, c_char) for f in range(1, i + 1)]
61 +class S(Structure):
62 +_fields_ = fields
63 +f = getattr(dll, "TestSize%d" % i)
64 +f.restype = S
65 +res = f()
66 +for i, f in enumerate(fields):
67 +value = getattr(res, f[0])
68 +expected = chr(ord('a') + i)
69 +self.assertEquals(value, expected)
70 +
71 +
72 +
55 73 @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
56 74 class TestWintypes(unittest.TestCase):
57 75 def test_HWND(self):
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1 +Fix returning structs from functions produced by MSVC
Original file line number Diff line number Diff line change
@@ -655,6 +655,200 @@ EXPORT(void) TwoOutArgs(int a, int *pi, int b, int *pj)
655 655 *pj += b;
656 656 }
657 657
658 +#ifdef MS_WIN32
659 +
660 +typedef struct {
661 +char f1;
662 +} Size1;
663 +
664 +typedef struct {
665 +char f1;
666 +char f2;
667 +} Size2;
668 +
669 +typedef struct {
670 +char f1;
671 +char f2;
672 +char f3;
673 +} Size3;
674 +
675 +typedef struct {
676 +char f1;
677 +char f2;
678 +char f3;
679 +char f4;
680 +} Size4;
681 +
682 +typedef struct {
683 +char f1;
684 +char f2;
685 +char f3;
686 +char f4;
687 +char f5;
688 +} Size5;
689 +
690 +typedef struct {
691 +char f1;
692 +char f2;
693 +char f3;
694 +char f4;
695 +char f5;
696 +char f6;
697 +} Size6;
698 +
699 +typedef struct {
700 +char f1;
701 +char f2;
702 +char f3;
703 +char f4;
704 +char f5;
705 +char f6;
706 +char f7;
707 +} Size7;
708 +
709 +typedef struct {
710 +char f1;
711 +char f2;
712 +char f3;
713 +char f4;
714 +char f5;
715 +char f6;
716 +char f7;
717 +char f8;
718 +} Size8;
719 +
720 +typedef struct {
721 +char f1;
722 +char f2;
723 +char f3;
724 +char f4;
725 +char f5;
726 +char f6;
727 +char f7;
728 +char f8;
729 +char f9;
730 +} Size9;
731 +
732 +typedef struct {
733 +char f1;
734 +char f2;
735 +char f3;
736 +char f4;
737 +char f5;
738 +char f6;
739 +char f7;
740 +char f8;
741 +char f9;
742 +char f10;
743 +} Size10;
744 +
745 +EXPORT(Size1) TestSize1() {
746 +Size1 f;
747 +f.f1 = 'a';
748 +return f;
749 +}
750 +
751 +EXPORT(Size2) TestSize2() {
752 +Size2 f;
753 +f.f1 = 'a';
754 +f.f2 = 'b';
755 +return f;
756 +}
757 +
758 +EXPORT(Size3) TestSize3() {
759 +Size3 f;
760 +f.f1 = 'a';
761 +f.f2 = 'b';
762 +f.f3 = 'c';
763 +return f;
764 +}
765 +
766 +EXPORT(Size4) TestSize4() {
767 +Size4 f;
768 +f.f1 = 'a';
769 +f.f2 = 'b';
770 +f.f3 = 'c';
771 +f.f4 = 'd';
772 +return f;
773 +}
774 +
775 +EXPORT(Size5) TestSize5() {
776 +Size5 f;
777 +f.f1 = 'a';
778 +f.f2 = 'b';
779 +f.f3 = 'c';
780 +f.f4 = 'd';
781 +f.f5 = 'e';
782 +return f;
783 +}
784 +
785 +EXPORT(Size6) TestSize6() {
786 +Size6 f;
787 +f.f1 = 'a';
788 +f.f2 = 'b';
789 +f.f3 = 'c';
790 +f.f4 = 'd';
791 +f.f5 = 'e';
792 +f.f6 = 'f';
793 +return f;
794 +}
795 +
796 +EXPORT(Size7) TestSize7() {
797 +Size7 f;
798 +f.f1 = 'a';
799 +f.f2 = 'b';
800 +f.f3 = 'c';
801 +f.f4 = 'd';
802 +f.f5 = 'e';
803 +f.f6 = 'f';
804 +f.f7 = 'g';
805 +return f;
806 +}
807 +
808 +EXPORT(Size8) TestSize8() {
809 +Size8 f;
810 +f.f1 = 'a';
811 +f.f2 = 'b';
812 +f.f3 = 'c';
813 +f.f4 = 'd';
814 +f.f5 = 'e';
815 +f.f6 = 'f';
816 +f.f7 = 'g';
817 +f.f8 = 'h';
818 +return f;
819 +}
820 +
821 +EXPORT(Size9) TestSize9() {
822 +Size9 f;
823 +f.f1 = 'a';
824 +f.f2 = 'b';
825 +f.f3 = 'c';
826 +f.f4 = 'd';
827 +f.f5 = 'e';
828 +f.f6 = 'f';
829 +f.f7 = 'g';
830 +f.f8 = 'h';
831 +f.f9 = 'i';
832 +return f;
833 +}
834 +
835 +EXPORT(Size10) TestSize10() {
836 +Size10 f;
837 +f.f1 = 'a';
838 +f.f2 = 'b';
839 +f.f3 = 'c';
840 +f.f4 = 'd';
841 +f.f5 = 'e';
842 +f.f6 = 'f';
843 +f.f7 = 'g';
844 +f.f8 = 'h';
845 +f.f9 = 'i';
846 +f.f10 = 'j';
847 +return f;
848 +}
849 +
850 +#endif
851 +
658 852 #ifdef MS_WIN32
659 853 EXPORT(S2H) __stdcall s_ret_2h_func(S2H inp) { return ret_2h_func(inp); }
660 854 EXPORT(S8I) __stdcall s_ret_8i_func(S8I inp) { return ret_8i_func(inp); }
Original file line number Diff line number Diff line change
@@ -747,9 +747,9 @@ ffi_type *_ctypes_get_ffi_type(PyObject *obj)
747 747 It returns small structures in registers
748 748 */
749 749 if (dict->ffi_type_pointer.type == FFI_TYPE_STRUCT) {
750 -if (dict->ffi_type_pointer.size <= 4)
750 +if (can_return_struct_as_int(dict->ffi_type_pointer.size))
751 751 return &ffi_type_sint32;
752 -else if (dict->ffi_type_pointer.size <= 8)
752 +else if (can_return_struct_as_sint64 (dict->ffi_type_pointer.size))
753 753 return &ffi_type_sint64;
754 754 }
755 755 #endif
Original file line number Diff line number Diff line change
@@ -126,6 +126,21 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
126 126 return;
127 127 }
128 128
129 +/*
130 +Per: https://msdn.microsoft.com/en-us/library/7572ztz4.aspx
131 +To be returned by value in RAX, user-defined types must have a length
132 +of 1, 2, 4, 8, 16, 32, or 64 bits
133 +*/
134 +int can_return_struct_as_int(size_t s)
135 +{
136 +return s == 1 |
137 +}
138 +
139 +int can_return_struct_as_sint64(size_t s)
140 +{
141 +return s == 8;
142 +}
143 +
129 144 /* Perform machine dependent cif processing */
130 145 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
131 146 {
@@ -144,9 +159,9 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
144 159 /* MSVC returns small structures in registers. Put in cif->flags
145 160 the value FFI_TYPE_STRUCT only if the structure is big enough;
146 161 otherwise, put the 4- or 8-bytes integer type. */
147 -if (cif->rtype->size <= 4)
162 +if (can_return_struct_as_int(cif->rtype->size))
148 163 cif->flags = FFI_TYPE_INT;
149 -else if (cif->rtype->size <= 8)
164 +else if (can_return_struct_as_sint64(cif->rtype->size))
150 165 cif->flags = FFI_TYPE_SINT64;
151 166 else
152 167 cif->flags = FFI_TYPE_STRUCT;
Original file line number Diff line number Diff line change
@@ -136,6 +136,9 @@ typedef struct _ffi_type
136 136 /*@null@*/ struct _ffi_type **elements;
137 137 } ffi_type;
138 138
139 +int can_return_struct_as_int(size_t);
140 +int can_return_struct_as_sint64(size_t);
141 +
139 142 /* These are defined in types.c */
140 143 extern ffi_type ffi_type_void;
141 144 extern ffi_type ffi_type_uint8;
Original file line number Diff line number Diff line change
@@ -117,7 +117,8 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
117 117 /* Make space for the return structure pointer */
118 118 if (cif->rtype->type == FFI_TYPE_STRUCT
119 119 #ifdef _WIN32
120 -&& (cif->rtype->size > 8) /* MSVC returns small structs in registers */
120 +&& !can_return_struct_as_int(cif->rtype->size) /* MSVC returns small structs in registers */
121 +&& !can_return_struct_as_sint64(cif->rtype->size)
121 122 #endif
122 123 #ifdef SPARC
123 124 && (cif->abi != FFI_V9 |
@@ -146,7 +147,9 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
146 147 bytes += sizeof(void*);
147 148 else
148 149 #elif defined (_WIN64)
149 -if ((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 8))
150 +if ((*ptr)->type == FFI_TYPE_STRUCT &&
151 + !can_return_struct_as_int((*ptr)->size) &&
152 + !can_return_struct_as_sint64((*ptr)->size))
150 153 bytes += sizeof(void*);
151 154 else
152 155 #endif