mirror of
https://github.com/python/cpython.git
synced 2025-12-04 00:30:19 +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)
|
||||
The constructor accepts any object with a truth value.
|
||||
|
||||
Additionally, if IEC 60559 compatible complex arithmetic (Annex G) is supported, the following
|
||||
complex types are available:
|
||||
Additionally, if IEC 60559 compatible complex arithmetic (Annex G) is supported
|
||||
in both C and ``libffi``, the following complex types are available:
|
||||
|
||||
+----------------------------------+---------------------------------+-----------------+
|
||||
| ctypes type | C type | Python type |
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import unittest
|
||||
from test.support import MS_WINDOWS
|
||||
import ctypes
|
||||
from ctypes import POINTER, c_void_p
|
||||
|
||||
|
|
@ -150,3 +151,20 @@ class PyCSimpleTypeAsMetaclassTest(unittest.TestCase):
|
|||
|
||||
self.assertIsInstance(POINTER(Sub), p_meta)
|
||||
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 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]
|
||||
_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");
|
||||
goto error;
|
||||
}
|
||||
if (!strchr(SIMPLE_TYPE_CHARS, *proto_str)) {
|
||||
fmt = _ctypes_get_fielddesc(proto_str);
|
||||
if (!fmt) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"class must define a '_type_' attribute which must be\n"
|
||||
"a single character string containing one of '%s'.",
|
||||
SIMPLE_TYPE_CHARS);
|
||||
goto error;
|
||||
}
|
||||
fmt = _ctypes_get_fielddesc(proto_str);
|
||||
if (fmt == NULL) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"_type_ '%s' not supported", proto_str);
|
||||
"a single character string containing one of the\n"
|
||||
"supported types: '%s'.",
|
||||
_ctypes_get_simple_type_chars());
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1255,6 +1255,10 @@ for code in 'sbBcdCEFgfhHiIlLqQPzuUZXvO':
|
|||
|
||||
// always contains NULLs:
|
||||
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;
|
||||
|
|
@ -1315,8 +1319,8 @@ _Py_COMP_DIAG_PUSH
|
|||
|
||||
/* Delayed initialization. Windows cannot statically reference dynamically
|
||||
loaded addresses from DLLs. */
|
||||
void
|
||||
_ctypes_init_fielddesc(void)
|
||||
static void
|
||||
_ctypes_init_fielddesc_locked(void)
|
||||
{
|
||||
/* Fixed-width integers */
|
||||
|
||||
|
|
@ -1432,9 +1436,11 @@ for base_code, base_c_type in [
|
|||
|
||||
TABLE_ENTRY_SW(d, &ffi_type_double);
|
||||
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
|
||||
TABLE_ENTRY(C, &ffi_type_complex_double);
|
||||
TABLE_ENTRY(E, &ffi_type_complex_float);
|
||||
TABLE_ENTRY(F, &ffi_type_complex_longdouble);
|
||||
if (Py_FFI_COMPLEX_AVAILABLE) {
|
||||
TABLE_ENTRY(C, &ffi_type_complex_double);
|
||||
TABLE_ENTRY(E, &ffi_type_complex_float);
|
||||
TABLE_ENTRY(F, &ffi_type_complex_longdouble);
|
||||
}
|
||||
#endif
|
||||
TABLE_ENTRY(g, &ffi_type_longdouble);
|
||||
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.setfunc = bool_set;
|
||||
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
|
||||
_Py_COMP_DIAG_POP
|
||||
|
||||
struct fielddesc *
|
||||
_ctypes_get_fielddesc(const char *fmt)
|
||||
static void
|
||||
_ctypes_init_fielddesc(void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
static PyMutex mutex = {0};
|
||||
PyMutex_Lock(&mutex);
|
||||
if (!initialized) {
|
||||
_ctypes_init_fielddesc();
|
||||
_ctypes_init_fielddesc_locked();
|
||||
initialized = true;
|
||||
}
|
||||
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;
|
||||
switch(fmt[0]) {
|
||||
/*[python input]
|
||||
|
|
|
|||
|
|
@ -5,8 +5,17 @@
|
|||
#include "pycore_moduleobject.h" // _PyModule_GetState()
|
||||
#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)
|
||||
# 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
|
||||
|
||||
#ifndef MS_WIN32
|
||||
|
|
@ -255,6 +264,9 @@ struct fielddesc {
|
|||
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 {
|
||||
PyObject_HEAD
|
||||
Py_ssize_t offset;
|
||||
|
|
|
|||
|
|
@ -407,7 +407,8 @@ Modules/_tkinter.c - trbInCmd -
|
|||
|
||||
## other
|
||||
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/_cursesmodule.c - curses_module_loaded -
|
||||
Modules/_cursesmodule.c - curses_initscr_called -
|
||||
|
|
@ -422,7 +423,6 @@ Modules/readline.c - libedit_history_start -
|
|||
##-----------------------
|
||||
## state
|
||||
|
||||
Modules/_ctypes/cfield.c - formattable -
|
||||
Modules/_ctypes/malloc_closure.c - free_list -
|
||||
Modules/_curses_panel.c - lop -
|
||||
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