8686#define DONT_USE_SEH
8787#endif
8888
89+ #if defined(__APPLE__ ) && __arm64__
90+ #define HAVE_FFI_PREP_CIF_VAR 1
91+ #endif
92+
8993#define CTYPES_CAPSULE_NAME_PYMEM "_ctypes pymem"
9094
9195static void pymem_destructor (PyObject * ptr )
@@ -812,7 +816,8 @@ static int _call_function_pointer(int flags,
812816 ffi_type * * atypes ,
813817 ffi_type * restype ,
814818 void * resmem ,
815- int argcount )
819+ int argcount ,
820+ int argtypecount )
816821{
817822 PyThreadState * _save = NULL ; /* For Py_BLOCK_THREADS and Py_UNBLOCK_THREADS */
818823 PyObject * error_object = NULL ;
@@ -835,15 +840,39 @@ static int _call_function_pointer(int flags,
835840 if ((flags & FUNCFLAG_CDECL ) == 0 )
836841 cc = FFI_STDCALL ;
837842#endif
838- if (FFI_OK != ffi_prep_cif (& cif ,
839- cc ,
840- argcount ,
841- restype ,
842- atypes )) {
843- PyErr_SetString (PyExc_RuntimeError ,
844- "ffi_prep_cif failed" );
845- return -1 ;
843+
844+ #if HAVE_FFI_PREP_CIF_VAR
845+ /* Everyone SHOULD set f.variadic=True on variadic function pointers, but
846+ * lots of existing code will not. If there's at least one arg and more
847+ * args are passed than are defined in the prototype, then it must be a
848+ * variadic function. */
849+ if ((flags & FUNCFLAG_VARIADIC ) ||
850+ (argtypecount != 0 && argcount > argtypecount ))
851+ {
852+ if (FFI_OK != ffi_prep_cif_var (& cif ,
853+ cc ,
854+ argtypecount ,
855+ argcount ,
856+ restype ,
857+ atypes )) {
858+ PyErr_SetString (PyExc_RuntimeError ,
859+ "ffi_prep_cif_var failed" );
860+ return -1 ;
861+ }
862+ } else {
863+ #endif
864+ if (FFI_OK != ffi_prep_cif (& cif ,
865+ cc ,
866+ argcount ,
867+ restype ,
868+ atypes )) {
869+ PyErr_SetString (PyExc_RuntimeError ,
870+ "ffi_prep_cif failed" );
871+ return -1 ;
872+ }
873+ #if HAVE_FFI_PREP_CIF_VAR
846874 }
875+ #endif
847876
848877 if (flags & (FUNCFLAG_USE_ERRNO | FUNCFLAG_USE_LASTERROR )) {
849878 error_object = _ctypes_get_errobj (& space );
@@ -1212,9 +1241,8 @@ PyObject *_ctypes_callproc(PPROC pProc,
12121241
12131242 if (-1 == _call_function_pointer (flags , pProc , avalues , atypes ,
12141243 rtype , resbuf ,
1215- Py_SAFE_DOWNCAST (argcount ,
1216- Py_ssize_t ,
1217- int )))
1244+ Py_SAFE_DOWNCAST (argcount , Py_ssize_t , int ),
1245+ Py_SAFE_DOWNCAST (argtype_count , Py_ssize_t , int )))
12181246 goto cleanup ;
12191247
12201248#ifdef WORDS_BIGENDIAN
0 commit comments