mirror of
https://github.com/python/cpython.git
synced 2025-12-04 16:43:27 +00:00
gh-128156: Guard use of ffi_type_complex_double on macOS system libffi (GH-128680)
* Determine ffi complex support at runtime * Also, generate SIMPLE_TYPE_CHARS once at runtime
This commit is contained in:
parent
7239da7559
commit
d3b1bb228c
7 changed files with 110 additions and 26 deletions
|
|
@ -266,8 +266,8 @@ Fundamental data types
|
||||||
(1)
|
(1)
|
||||||
The constructor accepts any object with a truth value.
|
The constructor accepts any object with a truth value.
|
||||||
|
|
||||||
Additionally, if IEC 60559 compatible complex arithmetic (Annex G) is supported, the following
|
Additionally, if IEC 60559 compatible complex arithmetic (Annex G) is supported
|
||||||
complex types are available:
|
in both C and ``libffi``, the following complex types are available:
|
||||||
|
|
||||||
+----------------------------------+---------------------------------+-----------------+
|
+----------------------------------+---------------------------------+-----------------+
|
||||||
| ctypes type | C type | Python type |
|
| ctypes type | C type | Python type |
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import unittest
|
import unittest
|
||||||
|
from test.support import MS_WINDOWS
|
||||||
import ctypes
|
import ctypes
|
||||||
from ctypes import POINTER, c_void_p
|
from ctypes import POINTER, c_void_p
|
||||||
|
|
||||||
|
|
@ -150,3 +151,20 @@ class PyCSimpleTypeAsMetaclassTest(unittest.TestCase):
|
||||||
|
|
||||||
self.assertIsInstance(POINTER(Sub), p_meta)
|
self.assertIsInstance(POINTER(Sub), p_meta)
|
||||||
self.assertIsSubclass(POINTER(Sub), Sub)
|
self.assertIsSubclass(POINTER(Sub), Sub)
|
||||||
|
|
||||||
|
def test_bad_type_message(self):
|
||||||
|
"""Verify the error message that lists all available type codes"""
|
||||||
|
# (The string is generated at runtime, so this checks the underlying
|
||||||
|
# set of types as well as correct construction of the string.)
|
||||||
|
with self.assertRaises(AttributeError) as cm:
|
||||||
|
class F(metaclass=PyCSimpleType):
|
||||||
|
_type_ = "\0"
|
||||||
|
message = str(cm.exception)
|
||||||
|
expected_type_chars = list('cbBhHiIlLdCEFfuzZqQPXOv?g')
|
||||||
|
if not hasattr(ctypes, 'c_float_complex'):
|
||||||
|
expected_type_chars.remove('C')
|
||||||
|
expected_type_chars.remove('E')
|
||||||
|
expected_type_chars.remove('F')
|
||||||
|
if not MS_WINDOWS:
|
||||||
|
expected_type_chars.remove('X')
|
||||||
|
self.assertIn("'" + ''.join(expected_type_chars) + "'", message)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
When using macOS system ``libffi``, support for complex types in
|
||||||
|
:mod:`ctypes` is now checked at runtime (macOS 10.15 or newer). The types
|
||||||
|
must also be available at build time.
|
||||||
|
|
@ -1776,11 +1776,6 @@ class _ctypes.c_void_p "PyObject *" "clinic_state_sub()->PyCSimpleType_Type"
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/
|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/
|
||||||
|
|
||||||
#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";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
_ctypes.c_wchar_p.from_param as c_wchar_p_from_param
|
_ctypes.c_wchar_p.from_param as c_wchar_p_from_param
|
||||||
|
|
@ -2252,17 +2247,13 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
"which must be a string of length 1");
|
"which must be a string of length 1");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (!strchr(SIMPLE_TYPE_CHARS, *proto_str)) {
|
fmt = _ctypes_get_fielddesc(proto_str);
|
||||||
|
if (!fmt) {
|
||||||
PyErr_Format(PyExc_AttributeError,
|
PyErr_Format(PyExc_AttributeError,
|
||||||
"class must define a '_type_' attribute which must be\n"
|
"class must define a '_type_' attribute which must be\n"
|
||||||
"a single character string containing one of '%s'.",
|
"a single character string containing one of the\n"
|
||||||
SIMPLE_TYPE_CHARS);
|
"supported types: '%s'.",
|
||||||
goto error;
|
_ctypes_get_simple_type_chars());
|
||||||
}
|
|
||||||
fmt = _ctypes_get_fielddesc(proto_str);
|
|
||||||
if (fmt == NULL) {
|
|
||||||
PyErr_Format(PyExc_ValueError,
|
|
||||||
"_type_ '%s' not supported", proto_str);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1255,6 +1255,10 @@ for code in 'sbBcdCEFgfhHiIlLqQPzuUZXvO':
|
||||||
|
|
||||||
// always contains NULLs:
|
// always contains NULLs:
|
||||||
struct fielddesc fmt_nil;
|
struct fielddesc fmt_nil;
|
||||||
|
|
||||||
|
// Result of _ctypes_get_simple_type_chars. Initialized just after
|
||||||
|
// the rest of formattable, so we stash it here.
|
||||||
|
char simple_type_chars[26];
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct formattable formattable;
|
static struct formattable formattable;
|
||||||
|
|
@ -1315,8 +1319,8 @@ _Py_COMP_DIAG_PUSH
|
||||||
|
|
||||||
/* Delayed initialization. Windows cannot statically reference dynamically
|
/* Delayed initialization. Windows cannot statically reference dynamically
|
||||||
loaded addresses from DLLs. */
|
loaded addresses from DLLs. */
|
||||||
void
|
static void
|
||||||
_ctypes_init_fielddesc(void)
|
_ctypes_init_fielddesc_locked(void)
|
||||||
{
|
{
|
||||||
/* Fixed-width integers */
|
/* Fixed-width integers */
|
||||||
|
|
||||||
|
|
@ -1432,9 +1436,11 @@ for base_code, base_c_type in [
|
||||||
|
|
||||||
TABLE_ENTRY_SW(d, &ffi_type_double);
|
TABLE_ENTRY_SW(d, &ffi_type_double);
|
||||||
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
|
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
|
||||||
TABLE_ENTRY(C, &ffi_type_complex_double);
|
if (Py_FFI_COMPLEX_AVAILABLE) {
|
||||||
TABLE_ENTRY(E, &ffi_type_complex_float);
|
TABLE_ENTRY(C, &ffi_type_complex_double);
|
||||||
TABLE_ENTRY(F, &ffi_type_complex_longdouble);
|
TABLE_ENTRY(E, &ffi_type_complex_float);
|
||||||
|
TABLE_ENTRY(F, &ffi_type_complex_longdouble);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
TABLE_ENTRY(g, &ffi_type_longdouble);
|
TABLE_ENTRY(g, &ffi_type_longdouble);
|
||||||
TABLE_ENTRY_SW(f, &ffi_type_float);
|
TABLE_ENTRY_SW(f, &ffi_type_float);
|
||||||
|
|
@ -1466,21 +1472,75 @@ for base_code, base_c_type in [
|
||||||
formattable.fmt_bool.code = '?';
|
formattable.fmt_bool.code = '?';
|
||||||
formattable.fmt_bool.setfunc = bool_set;
|
formattable.fmt_bool.setfunc = bool_set;
|
||||||
formattable.fmt_bool.getfunc = bool_get;
|
formattable.fmt_bool.getfunc = bool_get;
|
||||||
|
|
||||||
|
/*[python input]
|
||||||
|
all_chars = "cbBhHiIlLdCEFfuzZqQPXOv?g"
|
||||||
|
print(f' assert(sizeof(formattable.simple_type_chars) == {len(all_chars)+1});')
|
||||||
|
print(f' int i = 0;')
|
||||||
|
for char in all_chars:
|
||||||
|
ident_char = {'?': 'bool'}.get(char, char)
|
||||||
|
print(f" if (formattable.fmt_{ident_char}.code) "
|
||||||
|
+ f"formattable.simple_type_chars[i++] = '{char}';")
|
||||||
|
print(f" formattable.simple_type_chars[i] = 0;")
|
||||||
|
[python start generated code]*/
|
||||||
|
assert(sizeof(formattable.simple_type_chars) == 26);
|
||||||
|
int i = 0;
|
||||||
|
if (formattable.fmt_c.code) formattable.simple_type_chars[i++] = 'c';
|
||||||
|
if (formattable.fmt_b.code) formattable.simple_type_chars[i++] = 'b';
|
||||||
|
if (formattable.fmt_B.code) formattable.simple_type_chars[i++] = 'B';
|
||||||
|
if (formattable.fmt_h.code) formattable.simple_type_chars[i++] = 'h';
|
||||||
|
if (formattable.fmt_H.code) formattable.simple_type_chars[i++] = 'H';
|
||||||
|
if (formattable.fmt_i.code) formattable.simple_type_chars[i++] = 'i';
|
||||||
|
if (formattable.fmt_I.code) formattable.simple_type_chars[i++] = 'I';
|
||||||
|
if (formattable.fmt_l.code) formattable.simple_type_chars[i++] = 'l';
|
||||||
|
if (formattable.fmt_L.code) formattable.simple_type_chars[i++] = 'L';
|
||||||
|
if (formattable.fmt_d.code) formattable.simple_type_chars[i++] = 'd';
|
||||||
|
if (formattable.fmt_C.code) formattable.simple_type_chars[i++] = 'C';
|
||||||
|
if (formattable.fmt_E.code) formattable.simple_type_chars[i++] = 'E';
|
||||||
|
if (formattable.fmt_F.code) formattable.simple_type_chars[i++] = 'F';
|
||||||
|
if (formattable.fmt_f.code) formattable.simple_type_chars[i++] = 'f';
|
||||||
|
if (formattable.fmt_u.code) formattable.simple_type_chars[i++] = 'u';
|
||||||
|
if (formattable.fmt_z.code) formattable.simple_type_chars[i++] = 'z';
|
||||||
|
if (formattable.fmt_Z.code) formattable.simple_type_chars[i++] = 'Z';
|
||||||
|
if (formattable.fmt_q.code) formattable.simple_type_chars[i++] = 'q';
|
||||||
|
if (formattable.fmt_Q.code) formattable.simple_type_chars[i++] = 'Q';
|
||||||
|
if (formattable.fmt_P.code) formattable.simple_type_chars[i++] = 'P';
|
||||||
|
if (formattable.fmt_X.code) formattable.simple_type_chars[i++] = 'X';
|
||||||
|
if (formattable.fmt_O.code) formattable.simple_type_chars[i++] = 'O';
|
||||||
|
if (formattable.fmt_v.code) formattable.simple_type_chars[i++] = 'v';
|
||||||
|
if (formattable.fmt_bool.code) formattable.simple_type_chars[i++] = '?';
|
||||||
|
if (formattable.fmt_g.code) formattable.simple_type_chars[i++] = 'g';
|
||||||
|
formattable.simple_type_chars[i] = 0;
|
||||||
|
/*[python end generated code: output=e6e5098a02f4b606 input=72031a625eac00c1]*/
|
||||||
|
|
||||||
}
|
}
|
||||||
#undef FIXINT_FIELDDESC_FOR
|
#undef FIXINT_FIELDDESC_FOR
|
||||||
_Py_COMP_DIAG_POP
|
_Py_COMP_DIAG_POP
|
||||||
|
|
||||||
struct fielddesc *
|
static void
|
||||||
_ctypes_get_fielddesc(const char *fmt)
|
_ctypes_init_fielddesc(void)
|
||||||
{
|
{
|
||||||
static bool initialized = false;
|
static bool initialized = false;
|
||||||
static PyMutex mutex = {0};
|
static PyMutex mutex = {0};
|
||||||
PyMutex_Lock(&mutex);
|
PyMutex_Lock(&mutex);
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
_ctypes_init_fielddesc();
|
_ctypes_init_fielddesc_locked();
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
PyMutex_Unlock(&mutex);
|
PyMutex_Unlock(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
_ctypes_get_simple_type_chars(void) {
|
||||||
|
_ctypes_init_fielddesc();
|
||||||
|
return formattable.simple_type_chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fielddesc *
|
||||||
|
_ctypes_get_fielddesc(const char *fmt)
|
||||||
|
{
|
||||||
|
_ctypes_init_fielddesc();
|
||||||
|
|
||||||
struct fielddesc *result = NULL;
|
struct fielddesc *result = NULL;
|
||||||
switch(fmt[0]) {
|
switch(fmt[0]) {
|
||||||
/*[python input]
|
/*[python input]
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,17 @@
|
||||||
#include "pycore_moduleobject.h" // _PyModule_GetState()
|
#include "pycore_moduleobject.h" // _PyModule_GetState()
|
||||||
#include "pycore_typeobject.h" // _PyType_GetModuleState()
|
#include "pycore_typeobject.h" // _PyType_GetModuleState()
|
||||||
|
|
||||||
|
// Do we support C99 complex types in ffi?
|
||||||
|
// For Apple's libffi, this must be determined at runtime (see gh-128156).
|
||||||
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
|
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
|
||||||
# include "../_complex.h" // complex
|
# include "../_complex.h" // complex
|
||||||
|
# if USING_APPLE_OS_LIBFFI && defined(__has_builtin) && __has_builtin(__builtin_available)
|
||||||
|
# define Py_FFI_COMPLEX_AVAILABLE __builtin_available(macOS 10.15, *)
|
||||||
|
# else
|
||||||
|
# define Py_FFI_COMPLEX_AVAILABLE 1
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define Py_FFI_COMPLEX_AVAILABLE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MS_WIN32
|
#ifndef MS_WIN32
|
||||||
|
|
@ -255,6 +264,9 @@ struct fielddesc {
|
||||||
GETFUNC getfunc_swapped;
|
GETFUNC getfunc_swapped;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Get all single-character type codes (for use in error messages)
|
||||||
|
extern char *_ctypes_get_simple_type_chars(void);
|
||||||
|
|
||||||
typedef struct CFieldObject {
|
typedef struct CFieldObject {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
Py_ssize_t offset;
|
Py_ssize_t offset;
|
||||||
|
|
|
||||||
|
|
@ -407,7 +407,8 @@ Modules/_tkinter.c - trbInCmd -
|
||||||
|
|
||||||
## other
|
## other
|
||||||
Include/datetime.h - PyDateTimeAPI -
|
Include/datetime.h - PyDateTimeAPI -
|
||||||
Modules/_ctypes/cfield.c _ctypes_get_fielddesc initialized -
|
Modules/_ctypes/cfield.c _ctypes_init_fielddesc initialized -
|
||||||
|
Modules/_ctypes/cfield.c - formattable -
|
||||||
Modules/_ctypes/malloc_closure.c - _pagesize -
|
Modules/_ctypes/malloc_closure.c - _pagesize -
|
||||||
Modules/_cursesmodule.c - curses_module_loaded -
|
Modules/_cursesmodule.c - curses_module_loaded -
|
||||||
Modules/_cursesmodule.c - curses_initscr_called -
|
Modules/_cursesmodule.c - curses_initscr_called -
|
||||||
|
|
@ -422,7 +423,6 @@ Modules/readline.c - libedit_history_start -
|
||||||
##-----------------------
|
##-----------------------
|
||||||
## state
|
## state
|
||||||
|
|
||||||
Modules/_ctypes/cfield.c - formattable -
|
|
||||||
Modules/_ctypes/malloc_closure.c - free_list -
|
Modules/_ctypes/malloc_closure.c - free_list -
|
||||||
Modules/_curses_panel.c - lop -
|
Modules/_curses_panel.c - lop -
|
||||||
Modules/_ssl/debughelpers.c _PySSL_keylog_callback lock -
|
Modules/_ssl/debughelpers.c _PySSL_keylog_callback lock -
|
||||||
|
|
|
||||||
|
Can't render this file because it has a wrong number of fields in line 4.
|
Loading…
Add table
Add a link
Reference in a new issue