[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 |