https://github.com/python/cpython/commit/aac89b54c5ee03c4d64fbdfbb6ea3001e26aa83a
commit: aac89b54c5ee03c4d64fbdfbb6ea3001e26aa83a
branch: main
author: Mikhail Efimov <[email protected]>
committer: vstinner <[email protected]>
date: 2024-10-15T16:17:10Z
summary:

gh-125206: Bug in ctypes with old libffi is fixed (#125322)

Workaround for old libffi versions is added.
Module ctypes now supports C11 double complex only with libffi >= 3.3.0.

Co-authored-by: Sergey B Kirpichev <[email protected]>

files:
A Misc/NEWS.d/next/Library/2024-10-11-18-03-05.gh-issue-125206.pWRRK6.rst
M Lib/test/test_ctypes/test_libc.py
M Modules/_ctypes/_ctypes.c
M Modules/_ctypes/_ctypes_test.c
M Modules/_ctypes/callproc.c
M Modules/_ctypes/cfield.c
M Modules/_ctypes/ctypes.h
M configure
M configure.ac
M pyconfig.h.in

diff --git a/Lib/test/test_ctypes/test_libc.py 
b/Lib/test/test_ctypes/test_libc.py
index cab3cc9f46003a..df7dbc0ae264a0 100644
--- a/Lib/test/test_ctypes/test_libc.py
+++ b/Lib/test/test_ctypes/test_libc.py
@@ -23,7 +23,7 @@ def test_sqrt(self):
         self.assertEqual(lib.my_sqrt(2.0), math.sqrt(2.0))
 
     @unittest.skipUnless(hasattr(ctypes, "c_double_complex"),
-                         "requires C11 complex type")
+                         "requires C11 complex type and libffi >= 3.3.0")
     def test_csqrt(self):
         lib.my_csqrt.argtypes = ctypes.c_double_complex,
         lib.my_csqrt.restype = ctypes.c_double_complex
diff --git 
a/Misc/NEWS.d/next/Library/2024-10-11-18-03-05.gh-issue-125206.pWRRK6.rst 
b/Misc/NEWS.d/next/Library/2024-10-11-18-03-05.gh-issue-125206.pWRRK6.rst
new file mode 100644
index 00000000000000..ef7975ebcb376b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-11-18-03-05.gh-issue-125206.pWRRK6.rst
@@ -0,0 +1,2 @@
+Workaround for old libffi versions is added. Module ctypes supports
+:c:expr:`double complex` only with libffi >= 3.3.0. Patch by Mikhail Efimov.
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 8435ee4090b9e5..d6a5b75a03d3fe 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -1747,7 +1747,7 @@ class _ctypes.c_void_p "PyObject *" 
"clinic_state_sub()->PyCSimpleType_Type"
 [clinic start generated code]*/
 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/
 
-#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
+#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
 static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCEFfuzZqQPXOv?g";
 #else
 static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g";
diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c
index 5142bb81cf685c..7bac592fd38fb9 100644
--- a/Modules/_ctypes/_ctypes_test.c
+++ b/Modules/_ctypes/_ctypes_test.c
@@ -13,9 +13,7 @@
 
 #include <Python.h>
 
-#include <ffi.h>                  // FFI_TARGET_HAS_COMPLEX_TYPE
-
-#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
+#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
 #  include "../_complex.h"        // csqrt()
 #  undef I                        // for _ctypes_test_generated.c.h
 #endif
@@ -449,7 +447,7 @@ EXPORT(double) my_sqrt(double a)
     return sqrt(a);
 }
 
-#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
+#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
 EXPORT(double complex) my_csqrt(double complex a)
 {
     return csqrt(a);
diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c
index fd89d9c67b3fc0..5ac9cf16681645 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -105,7 +105,7 @@ module _ctypes
 #include "pycore_global_objects.h"// _Py_ID()
 #include "pycore_traceback.h"     // _PyTraceback_Add()
 
-#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
+#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
 #include "../_complex.h"          // complex
 #endif
 
@@ -655,7 +655,7 @@ union result {
     double d;
     float f;
     void *p;
-#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
+#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
     double complex C;
     float complex E;
     long double complex F;
diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c
index 53a946e750b866..3220852c8398e0 100644
--- a/Modules/_ctypes/cfield.c
+++ b/Modules/_ctypes/cfield.c
@@ -14,7 +14,7 @@
 #include <ffi.h>
 #include "ctypes.h"
 
-#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
+#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
 #  include "../_complex.h"        // complex
 #endif
 
@@ -972,7 +972,7 @@ d_get(void *ptr, Py_ssize_t size)
     return PyFloat_FromDouble(val);
 }
 
-#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
+#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
 static PyObject *
 C_set(void *ptr, PyObject *value, Py_ssize_t size)
 {
@@ -1545,7 +1545,7 @@ static struct fielddesc formattable[] = {
     { 'B', B_set, B_get, NULL},
     { 'c', c_set, c_get, NULL},
     { 'd', d_set, d_get, NULL, d_set_sw, d_get_sw},
-#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
+#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
     { 'C', C_set, C_get, NULL},
     { 'E', E_set, E_get, NULL},
     { 'F', F_set, F_get, NULL},
@@ -1600,7 +1600,7 @@ _ctypes_init_fielddesc(void)
         case 'B': fd->pffi_type = &ffi_type_uchar; break;
         case 'c': fd->pffi_type = &ffi_type_schar; break;
         case 'd': fd->pffi_type = &ffi_type_double; break;
-#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
+#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
         case 'C': fd->pffi_type = &ffi_type_complex_double; break;
         case 'E': fd->pffi_type = &ffi_type_complex_float; break;
         case 'F': fd->pffi_type = &ffi_type_complex_longdouble; break;
diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h
index 738dcd1aaf8a01..7e0804054cded4 100644
--- a/Modules/_ctypes/ctypes.h
+++ b/Modules/_ctypes/ctypes.h
@@ -2,12 +2,10 @@
 #   include <alloca.h>
 #endif
 
-#include <ffi.h>                  // FFI_TARGET_HAS_COMPLEX_TYPE
-
 #include "pycore_moduleobject.h"  // _PyModule_GetState()
 #include "pycore_typeobject.h"    // _PyType_GetModuleState()
 
-#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
+#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
 #   include "../_complex.h"       // complex
 #endif
 
@@ -388,7 +386,7 @@ struct tagPyCArgObject {
         double d;
         float f;
         void *p;
-#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
+#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
         double complex C;
         float complex E;
         long double complex F;
diff --git a/configure b/configure
index be119f108a060b..17c70d25f9e70c 100755
--- a/configure
+++ b/configure
@@ -15050,6 +15050,70 @@ LIBS=$save_LIBS
 
 
 
+fi
+
+# Check for libffi with real complex double support.
+# This is a workaround, since FFI_TARGET_HAS_COMPLEX_TYPE was defined in 
libffi v3.2.1,
+# but real support was provided only in libffi v3.3.0.
+# See https://github.com/python/cpython/issues/125206 for more details.
+#
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking libffi has complex type 
support" >&5
+printf %s "checking libffi has complex type support... " >&6; }
+if test ${ac_cv_ffi_complex_double_supported+y}
+then :
+  printf %s "(cached) " >&6
+else $as_nop
+  ac_save_cc="$CC"
+CC="$CC -lffi"
+if test "$cross_compiling" = yes
+then :
+  ac_cv_ffi_complex_double_supported=no
+else $as_nop
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <complex.h>
+#include <ffi.h>
+int z_is_expected(double complex z)
+{
+    const double complex expected = CMPLX(1.25, -0.5);
+    return z == expected;
+}
+int main(void)
+{
+    double complex z = 1.25 - 0.5 * I;
+    ffi_type *args[1] = {&ffi_type_complex_double};
+    void *values[1] = {&z};
+    ffi_cif cif;
+    if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+        &ffi_type_sint, args) != FFI_OK)
+    {
+        return 2;
+    }
+    ffi_arg rc;
+    ffi_call(&cif, FFI_FN(z_is_expected), &rc, values);
+    return !rc;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"
+then :
+  ac_cv_ffi_complex_double_supported=yes
+else $as_nop
+  ac_cv_ffi_complex_double_supported=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+CC="$ac_save_cc"
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: 
$ac_cv_ffi_complex_double_supported" >&5
+printf "%s\n" "$ac_cv_ffi_complex_double_supported" >&6; }
+if test "$ac_cv_ffi_complex_double_supported" = "yes"; then
+
+printf "%s\n" "#define Py_FFI_SUPPORT_C_COMPLEX 1" >>confdefs.h
+
 fi
 
 # Check for use of the system libmpdec library
diff --git a/configure.ac b/configure.ac
index 582851695e400f..56daa8b0f79bc0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4089,6 +4089,46 @@ AS_VAR_IF([have_libffi], [yes], [
   ])
 ])
 
+# Check for libffi with real complex double support.
+# This is a workaround, since FFI_TARGET_HAS_COMPLEX_TYPE was defined in 
libffi v3.2.1,
+# but real support was provided only in libffi v3.3.0.
+# See https://github.com/python/cpython/issues/125206 for more details.
+#
+AC_CACHE_CHECK([libffi has complex type support], 
[ac_cv_ffi_complex_double_supported],
+[ac_save_cc="$CC"
+CC="$CC -lffi"
+AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include <complex.h>
+#include <ffi.h>
+int z_is_expected(double complex z)
+{
+    const double complex expected = CMPLX(1.25, -0.5);
+    return z == expected;
+}
+int main(void)
+{
+    double complex z = 1.25 - 0.5 * I;
+    ffi_type *args[1] = {&ffi_type_complex_double};
+    void *values[1] = {&z};
+    ffi_cif cif;
+    if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+        &ffi_type_sint, args) != FFI_OK)
+    {
+        return 2;
+    }
+    ffi_arg rc;
+    ffi_call(&cif, FFI_FN(z_is_expected), &rc, values);
+    return !rc;
+}
+]])], [ac_cv_ffi_complex_double_supported=yes],
+[ac_cv_ffi_complex_double_supported=no],
+[ac_cv_ffi_complex_double_supported=no])
+CC="$ac_save_cc"])
+if test "$ac_cv_ffi_complex_double_supported" = "yes"; then
+    AC_DEFINE([Py_FFI_SUPPORT_C_COMPLEX], [1],
+              [Defined if _Complex C type can be used with libffi.])
+fi
+
 # Check for use of the system libmpdec library
 AC_MSG_CHECKING([for --with-system-libmpdec])
 AC_ARG_WITH(
diff --git a/pyconfig.h.in b/pyconfig.h.in
index 1947d8ee14f83e..fb9ab1e78dc7e1 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -1685,6 +1685,9 @@
 /* Defined if Python is built as a shared library. */
 #undef Py_ENABLE_SHARED
 
+/* Defined if _Complex C type can be used with libffi. */
+#undef Py_FFI_SUPPORT_C_COMPLEX
+
 /* Define if you want to disable the GIL */
 #undef Py_GIL_DISABLED
 

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to