New upstream release.
Kali Janitor
2 years ago
0 | Metadata-Version: 1.1 | |
0 | Metadata-Version: 2.1 | |
1 | 1 | Name: cffi |
2 | Version: 1.14.0 | |
2 | Version: 1.14.6 | |
3 | 3 | Summary: Foreign Function Interface for Python calling C code. |
4 | 4 | Home-page: http://cffi.readthedocs.org |
5 | 5 | Author: Armin Rigo, Maciej Fijalkowski |
6 | 6 | Author-email: [email protected] |
7 | 7 | License: MIT |
8 | Description: | |
9 | CFFI | |
10 | ==== | |
11 | ||
12 | Foreign Function Interface for Python calling C code. | |
13 | Please see the `Documentation <http://cffi.readthedocs.org/>`_. | |
14 | ||
15 | Contact | |
16 | ------- | |
17 | ||
18 | `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_ | |
19 | ||
20 | 8 | Platform: UNKNOWN |
21 | 9 | Classifier: Programming Language :: Python |
22 | 10 | Classifier: Programming Language :: Python :: 2 |
31 | 19 | Classifier: Programming Language :: Python :: Implementation :: CPython |
32 | 20 | Classifier: Programming Language :: Python :: Implementation :: PyPy |
33 | 21 | Classifier: License :: OSI Approved :: MIT License |
22 | License-File: LICENSE | |
23 | ||
24 | ||
25 | CFFI | |
26 | ==== | |
27 | ||
28 | Foreign Function Interface for Python calling C code. | |
29 | Please see the `Documentation <http://cffi.readthedocs.org/>`_. | |
30 | ||
31 | Contact | |
32 | ------- | |
33 | ||
34 | `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_ | |
35 | ||
36 |
1 | 1 | #include <Python.h> |
2 | 2 | #include "structmember.h" |
3 | 3 | |
4 | #define CFFI_VERSION "1.14.0" | |
4 | #define CFFI_VERSION "1.14.6" | |
5 | 5 | |
6 | 6 | #ifdef MS_WIN32 |
7 | 7 | #include <windows.h> |
79 | 79 | * That sounds like a horribly bad idea to me, and is the reason for why |
80 | 80 | * I prefer CFFI crashing cleanly. |
81 | 81 | * |
82 | * Currently, we use libffi's ffi_closure_alloc() only on NetBSD. It is | |
82 | * Currently, we use libffi's ffi_closure_alloc() on NetBSD. It is | |
83 | 83 | * known that on the NetBSD kernel, a different strategy is used which |
84 | 84 | * should not be open to the fork() bug. |
85 | * | |
86 | * This is also used on macOS, provided we are executing on macOS 10.15 or | |
87 | * above. It's a mess because it needs runtime checks in that case. | |
85 | 88 | */ |
86 | 89 | #ifdef __NetBSD__ |
87 | # define CFFI_TRUST_LIBFFI | |
90 | ||
91 | # define CFFI_CHECK_FFI_CLOSURE_ALLOC 1 | |
92 | # define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 1 | |
93 | # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC 1 | |
94 | # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 1 | |
95 | # define CFFI_CHECK_FFI_PREP_CIF_VAR 0 | |
96 | # define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 0 | |
97 | ||
98 | #elif defined(__APPLE__) && defined(FFI_AVAILABLE_APPLE) | |
99 | ||
100 | # define CFFI_CHECK_FFI_CLOSURE_ALLOC __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *) | |
101 | # define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 1 | |
102 | # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *) | |
103 | # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 1 | |
104 | # define CFFI_CHECK_FFI_PREP_CIF_VAR __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *) | |
105 | # define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 1 | |
106 | ||
107 | #else | |
108 | ||
109 | # define CFFI_CHECK_FFI_CLOSURE_ALLOC 0 | |
110 | # define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 0 | |
111 | # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC 0 | |
112 | # define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 0 | |
113 | # define CFFI_CHECK_FFI_PREP_CIF_VAR 0 | |
114 | # define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 0 | |
115 | ||
88 | 116 | #endif |
89 | 117 | |
90 | #ifndef CFFI_TRUST_LIBFFI | |
91 | # include "malloc_closure.h" | |
92 | #endif | |
118 | /* always includes this, even if it turns out not to be used on NetBSD | |
119 | because calls are behind "if (0)" */ | |
120 | #include "malloc_closure.h" | |
93 | 121 | |
94 | 122 | |
95 | 123 | #if PY_MAJOR_VERSION >= 3 |
147 | 175 | (PyCObject_FromVoidPtr(pointer, destructor)) |
148 | 176 | #endif |
149 | 177 | |
178 | #if PY_VERSION_HEX < 0x030900a4 | |
179 | # define Py_SET_REFCNT(obj, val) (Py_REFCNT(obj) = (val)) | |
180 | #endif | |
181 | ||
182 | #if PY_VERSION_HEX >= 0x03080000 | |
183 | # define USE_WRITEUNRAISABLEMSG | |
184 | #endif | |
185 | ||
150 | 186 | /************************************************************/ |
151 | 187 | |
152 | 188 | /* base type flag: exactly one of the following: */ |
403 | 439 | |
404 | 440 | if (ct->ct_unique_key != NULL) { |
405 | 441 | /* revive dead object temporarily for DelItem */ |
406 | Py_REFCNT(ct) = 43; | |
442 | Py_SET_REFCNT(ct, 43); | |
407 | 443 | PyDict_DelItem(unique_cache, ct->ct_unique_key); |
408 | 444 | assert(Py_REFCNT(ct) == 42); |
409 | Py_REFCNT(ct) = 0; | |
445 | Py_SET_REFCNT(ct, 0); | |
410 | 446 | Py_DECREF(ct->ct_unique_key); |
411 | 447 | } |
412 | 448 | Py_XDECREF(ct->ct_itemdescr); |
652 | 688 | |
653 | 689 | static PyTypeObject CTypeDescr_Type = { |
654 | 690 | PyVarObject_HEAD_INIT(NULL, 0) |
655 | "_cffi_backend.CTypeDescr", | |
691 | "_cffi_backend.CType", | |
656 | 692 | offsetof(CTypeDescrObject, ct_name), |
657 | 693 | sizeof(char), |
658 | 694 | (destructor)ctypedescr_dealloc, /* tp_dealloc */ |
1885 | 1921 | ffi_closure *closure = ((CDataObject_closure *)cd)->closure; |
1886 | 1922 | PyObject *args = (PyObject *)(closure->user_data); |
1887 | 1923 | Py_XDECREF(args); |
1888 | #ifdef CFFI_TRUST_LIBFFI | |
1889 | ffi_closure_free(closure); | |
1890 | #else | |
1891 | cffi_closure_free(closure); | |
1924 | #if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE | |
1925 | if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { | |
1926 | ffi_closure_free(closure); | |
1927 | } else | |
1892 | 1928 | #endif |
1929 | cffi_closure_free(closure); | |
1893 | 1930 | } |
1894 | 1931 | else { |
1895 | 1932 | Py_FatalError("cdata CDataOwningGC_Type with unexpected type flags"); |
2887 | 2924 | convert_struct_to_owning_object(char *data, CTypeDescrObject *ct); /*forward*/ |
2888 | 2925 | |
2889 | 2926 | static cif_description_t * |
2890 | fb_prepare_cif(PyObject *fargs, CTypeDescrObject *, ffi_abi); /*forward*/ | |
2927 | fb_prepare_cif(PyObject *fargs, CTypeDescrObject *, Py_ssize_t, ffi_abi); | |
2928 | /*forward*/ | |
2891 | 2929 | |
2892 | 2930 | static PyObject *new_primitive_type(const char *name); /*forward*/ |
2893 | 2931 | |
3080 | 3118 | #else |
3081 | 3119 | fabi = PyLong_AS_LONG(PyTuple_GET_ITEM(signature, 0)); |
3082 | 3120 | #endif |
3083 | cif_descr = fb_prepare_cif(fvarargs, fresult, fabi); | |
3121 | cif_descr = fb_prepare_cif(fvarargs, fresult, nargs_declared, fabi); | |
3084 | 3122 | if (cif_descr == NULL) |
3085 | 3123 | goto error; |
3086 | 3124 | } |
3353 | 3391 | |
3354 | 3392 | static PyTypeObject CData_Type = { |
3355 | 3393 | PyVarObject_HEAD_INIT(NULL, 0) |
3356 | "_cffi_backend.CData", | |
3394 | "_cffi_backend._CDataBase", | |
3357 | 3395 | sizeof(CDataObject), |
3358 | 3396 | 0, |
3359 | 3397 | (destructor)cdata_dealloc, /* tp_dealloc */ |
3372 | 3410 | (setattrofunc)cdata_setattro, /* tp_setattro */ |
3373 | 3411 | 0, /* tp_as_buffer */ |
3374 | 3412 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ |
3375 | 0, /* tp_doc */ | |
3413 | "The internal base type for CData objects. Use FFI.CData to access " | |
3414 | "it. Always check with isinstance(): subtypes are sometimes returned " | |
3415 | "on CPython, for performance reasons.", /* tp_doc */ | |
3376 | 3416 | 0, /* tp_traverse */ |
3377 | 3417 | 0, /* tp_clear */ |
3378 | 3418 | cdata_richcompare, /* tp_richcompare */ |
3395 | 3435 | |
3396 | 3436 | static PyTypeObject CDataOwning_Type = { |
3397 | 3437 | PyVarObject_HEAD_INIT(NULL, 0) |
3398 | "_cffi_backend.CDataOwn", | |
3438 | "_cffi_backend.__CDataOwn", | |
3399 | 3439 | sizeof(CDataObject), |
3400 | 3440 | 0, |
3401 | 3441 | (destructor)cdataowning_dealloc, /* tp_dealloc */ |
3414 | 3454 | 0, /* inherited */ /* tp_setattro */ |
3415 | 3455 | 0, /* tp_as_buffer */ |
3416 | 3456 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ |
3417 | 0, /* tp_doc */ | |
3457 | "This is an internal subtype of _CDataBase for performance only on " | |
3458 | "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */ | |
3418 | 3459 | 0, /* tp_traverse */ |
3419 | 3460 | 0, /* tp_clear */ |
3420 | 3461 | 0, /* inherited */ /* tp_richcompare */ |
3437 | 3478 | |
3438 | 3479 | static PyTypeObject CDataOwningGC_Type = { |
3439 | 3480 | PyVarObject_HEAD_INIT(NULL, 0) |
3440 | "_cffi_backend.CDataOwnGC", | |
3481 | "_cffi_backend.__CDataOwnGC", | |
3441 | 3482 | sizeof(CDataObject_own_structptr), |
3442 | 3483 | 0, |
3443 | 3484 | (destructor)cdataowninggc_dealloc, /* tp_dealloc */ |
3457 | 3498 | 0, /* tp_as_buffer */ |
3458 | 3499 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */ |
3459 | 3500 | | Py_TPFLAGS_HAVE_GC, |
3460 | 0, /* tp_doc */ | |
3501 | "This is an internal subtype of _CDataBase for performance only on " | |
3502 | "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */ | |
3461 | 3503 | (traverseproc)cdataowninggc_traverse, /* tp_traverse */ |
3462 | 3504 | (inquiry)cdataowninggc_clear, /* tp_clear */ |
3463 | 3505 | 0, /* inherited */ /* tp_richcompare */ |
3480 | 3522 | |
3481 | 3523 | static PyTypeObject CDataFromBuf_Type = { |
3482 | 3524 | PyVarObject_HEAD_INIT(NULL, 0) |
3483 | "_cffi_backend.CDataFromBuf", | |
3525 | "_cffi_backend.__CDataFromBuf", | |
3484 | 3526 | sizeof(CDataObject_frombuf), |
3485 | 3527 | 0, |
3486 | 3528 | (destructor)cdatafrombuf_dealloc, /* tp_dealloc */ |
3500 | 3542 | 0, /* tp_as_buffer */ |
3501 | 3543 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */ |
3502 | 3544 | | Py_TPFLAGS_HAVE_GC, |
3503 | 0, /* tp_doc */ | |
3545 | "This is an internal subtype of _CDataBase for performance only on " | |
3546 | "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */ | |
3504 | 3547 | (traverseproc)cdatafrombuf_traverse, /* tp_traverse */ |
3505 | 3548 | (inquiry)cdatafrombuf_clear, /* tp_clear */ |
3506 | 3549 | 0, /* inherited */ /* tp_richcompare */ |
3523 | 3566 | |
3524 | 3567 | static PyTypeObject CDataGCP_Type = { |
3525 | 3568 | PyVarObject_HEAD_INIT(NULL, 0) |
3526 | "_cffi_backend.CDataGCP", | |
3569 | "_cffi_backend.__CDataGCP", | |
3527 | 3570 | sizeof(CDataObject_gcp), |
3528 | 3571 | 0, |
3529 | 3572 | (destructor)cdatagcp_dealloc, /* tp_dealloc */ |
3546 | 3589 | | Py_TPFLAGS_HAVE_FINALIZE |
3547 | 3590 | #endif |
3548 | 3591 | | Py_TPFLAGS_HAVE_GC, |
3549 | 0, /* tp_doc */ | |
3592 | "This is an internal subtype of _CDataBase for performance only on " | |
3593 | "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */ | |
3550 | 3594 | (traverseproc)cdatagcp_traverse, /* tp_traverse */ |
3551 | 3595 | 0, /* tp_clear */ |
3552 | 3596 | 0, /* inherited */ /* tp_richcompare */ |
3607 | 3651 | |
3608 | 3652 | static PyTypeObject CDataIter_Type = { |
3609 | 3653 | PyVarObject_HEAD_INIT(NULL, 0) |
3610 | "_cffi_backend.CDataIter", /* tp_name */ | |
3654 | "_cffi_backend.__CData_iterator", /* tp_name */ | |
3611 | 3655 | sizeof(CDataIterObject), /* tp_basicsize */ |
3612 | 3656 | 0, /* tp_itemsize */ |
3613 | 3657 | /* methods */ |
4362 | 4406 | |
4363 | 4407 | static PyTypeObject dl_type = { |
4364 | 4408 | PyVarObject_HEAD_INIT(NULL, 0) |
4365 | "_cffi_backend.Library", /* tp_name */ | |
4409 | "_cffi_backend.CLibrary", /* tp_name */ | |
4366 | 4410 | sizeof(DynLibObject), /* tp_basicsize */ |
4367 | 4411 | 0, /* tp_itemsize */ |
4368 | 4412 | /* methods */ |
4440 | 4484 | { |
4441 | 4485 | PyObject *s = PyTuple_GET_ITEM(args, 0); |
4442 | 4486 | #ifdef MS_WIN32 |
4443 | Py_UNICODE *filenameW; | |
4444 | if (PyArg_ParseTuple(args, "u|i:load_library", &filenameW, &flags)) | |
4487 | PyObject *filename_unicode; | |
4488 | if (PyArg_ParseTuple(args, "U|i:load_library", &filename_unicode, &flags)) | |
4445 | 4489 | { |
4490 | Py_ssize_t sz1; | |
4491 | wchar_t *w1; | |
4446 | 4492 | #if PY_MAJOR_VERSION < 3 |
4447 | 4493 | s = PyUnicode_AsUTF8String(s); |
4448 | 4494 | if (s == NULL) |
4453 | 4499 | if (*p_printable_filename == NULL) |
4454 | 4500 | return NULL; |
4455 | 4501 | |
4456 | handle = dlopenW(filenameW); | |
4502 | sz1 = PyUnicode_GetSize(filename_unicode) + 1; | |
4503 | sz1 *= 2; /* should not be needed, but you never know */ | |
4504 | w1 = alloca(sizeof(wchar_t) * sz1); | |
4505 | sz1 = PyUnicode_AsWideChar((PyUnicodeObject *)filename_unicode, | |
4506 | w1, sz1 - 1); | |
4507 | if (sz1 < 0) | |
4508 | return NULL; | |
4509 | w1[sz1] = 0; | |
4510 | handle = dlopenW(w1); | |
4457 | 4511 | goto got_handle; |
4458 | 4512 | } |
4459 | 4513 | PyErr_Clear(); |
4465 | 4519 | if (PyUnicode_Check(s)) |
4466 | 4520 | { |
4467 | 4521 | s = PyUnicode_AsUTF8String(s); |
4468 | if (s == NULL) | |
4522 | if (s == NULL) { | |
4523 | PyMem_Free(filename_or_null); | |
4469 | 4524 | return NULL; |
4525 | } | |
4470 | 4526 | *p_temp = s; |
4471 | 4527 | } |
4472 | 4528 | #endif |
4473 | 4529 | *p_printable_filename = PyText_AsUTF8(s); |
4474 | if (*p_printable_filename == NULL) | |
4530 | if (*p_printable_filename == NULL) { | |
4531 | PyMem_Free(filename_or_null); | |
4475 | 4532 | return NULL; |
4533 | } | |
4476 | 4534 | } |
4477 | 4535 | if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0) |
4478 | 4536 | flags |= RTLD_NOW; |
4479 | 4537 | |
4538 | #ifdef MS_WIN32 | |
4539 | if (filename_or_null == NULL) { | |
4540 | PyErr_SetString(PyExc_OSError, "dlopen(None) not supported on Windows"); | |
4541 | return NULL; | |
4542 | } | |
4543 | #endif | |
4544 | ||
4480 | 4545 | handle = dlopen(filename_or_null, flags); |
4546 | PyMem_Free(filename_or_null); | |
4481 | 4547 | |
4482 | 4548 | #ifdef MS_WIN32 |
4483 | 4549 | got_handle: |
4994 | 5060 | #ifdef MS_WIN32 |
4995 | 5061 | sflags |= SF_MSVC_BITFIELDS; |
4996 | 5062 | #else |
4997 | # if defined(__arm__) || defined(__aarch64__) | |
5063 | # if defined(__APPLE__) && defined(__arm64__) | |
5064 | sflags |= SF_GCC_X86_BITFIELDS; | |
5065 | # elif defined(__arm__) || defined(__aarch64__) | |
4998 | 5066 | sflags |= SF_GCC_ARM_BITFIELDS; |
4999 | 5067 | # else |
5000 | 5068 | sflags |= SF_GCC_X86_BITFIELDS; |
5782 | 5850 | |
5783 | 5851 | static cif_description_t *fb_prepare_cif(PyObject *fargs, |
5784 | 5852 | CTypeDescrObject *fresult, |
5853 | Py_ssize_t variadic_nargs_declared, | |
5785 | 5854 | ffi_abi fabi) |
5855 | ||
5786 | 5856 | { |
5787 | 5857 | char *buffer; |
5788 | 5858 | cif_description_t *cif_descr; |
5789 | 5859 | struct funcbuilder_s funcbuffer; |
5860 | ffi_status status = (ffi_status)-1; | |
5790 | 5861 | |
5791 | 5862 | funcbuffer.nb_bytes = 0; |
5792 | 5863 | funcbuffer.bufferp = NULL; |
5809 | 5880 | assert(funcbuffer.bufferp == buffer + funcbuffer.nb_bytes); |
5810 | 5881 | |
5811 | 5882 | cif_descr = (cif_description_t *)buffer; |
5812 | if (ffi_prep_cif(&cif_descr->cif, fabi, funcbuffer.nargs, | |
5813 | funcbuffer.rtype, funcbuffer.atypes) != FFI_OK) { | |
5883 | ||
5884 | /* use `ffi_prep_cif_var` if necessary and available */ | |
5885 | #if CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE | |
5886 | if (variadic_nargs_declared >= 0) { | |
5887 | if (CFFI_CHECK_FFI_PREP_CIF_VAR) { | |
5888 | status = ffi_prep_cif_var(&cif_descr->cif, fabi, | |
5889 | variadic_nargs_declared, funcbuffer.nargs, | |
5890 | funcbuffer.rtype, funcbuffer.atypes); | |
5891 | } | |
5892 | } | |
5893 | #endif | |
5894 | ||
5895 | if (status == (ffi_status)-1) { | |
5896 | status = ffi_prep_cif(&cif_descr->cif, fabi, funcbuffer.nargs, | |
5897 | funcbuffer.rtype, funcbuffer.atypes); | |
5898 | } | |
5899 | ||
5900 | if (status != FFI_OK) { | |
5814 | 5901 | PyErr_SetString(PyExc_SystemError, |
5815 | 5902 | "libffi failed to build this function type"); |
5816 | 5903 | goto error; |
5854 | 5941 | is computed here. */ |
5855 | 5942 | cif_description_t *cif_descr; |
5856 | 5943 | |
5857 | cif_descr = fb_prepare_cif(fargs, fresult, fabi); | |
5944 | cif_descr = fb_prepare_cif(fargs, fresult, -1, fabi); | |
5858 | 5945 | if (cif_descr == NULL) { |
5859 | 5946 | if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { |
5860 | 5947 | PyErr_Clear(); /* will get the exception if we see an |
5982 | 6069 | char *extra_error_line) |
5983 | 6070 | { |
5984 | 6071 | /* like PyErr_WriteUnraisable(), but write a full traceback */ |
6072 | #ifdef USE_WRITEUNRAISABLEMSG | |
6073 | ||
6074 | /* PyErr_WriteUnraisable actually writes the full traceback anyway | |
6075 | from Python 3.4, but we can't really get the formatting of the | |
6076 | custom text to be what we want. We can do better from Python | |
6077 | 3.8 by calling the new _PyErr_WriteUnraisableMsg(). | |
6078 | Luckily it's also Python 3.8 that adds new functionality that | |
6079 | people might want: the new sys.unraisablehook(). | |
6080 | */ | |
6081 | PyObject *s; | |
6082 | int first_char; | |
6083 | assert(objdescr != NULL && objdescr[0] != 0); /* non-empty */ | |
6084 | first_char = objdescr[0]; | |
6085 | if (first_char >= 'A' && first_char <= 'Z') | |
6086 | first_char += 'a' - 'A'; /* lower() the very first character */ | |
6087 | if (extra_error_line == NULL) | |
6088 | extra_error_line = ""; | |
6089 | ||
6090 | if (obj != NULL) | |
6091 | s = PyUnicode_FromFormat("%c%s%R%s", | |
6092 | first_char, objdescr + 1, obj, extra_error_line); | |
6093 | else | |
6094 | s = PyUnicode_FromFormat("%c%s%s", | |
6095 | first_char, objdescr + 1, extra_error_line); | |
6096 | ||
6097 | PyErr_Restore(t, v, tb); | |
6098 | if (s != NULL) { | |
6099 | _PyErr_WriteUnraisableMsg(PyText_AS_UTF8(s), NULL); | |
6100 | Py_DECREF(s); | |
6101 | } | |
6102 | else | |
6103 | PyErr_WriteUnraisable(obj); /* best effort */ | |
6104 | PyErr_Clear(); | |
6105 | ||
6106 | #else | |
6107 | ||
6108 | /* version for Python 2.7 and < 3.8 */ | |
5985 | 6109 | PyObject *f; |
5986 | 6110 | #if PY_MAJOR_VERSION >= 3 |
5987 | 6111 | /* jump through hoops to ensure the tb is attached to v, on Python 3 */ |
6006 | 6130 | Py_XDECREF(t); |
6007 | 6131 | Py_XDECREF(v); |
6008 | 6132 | Py_XDECREF(tb); |
6133 | ||
6134 | #endif | |
6009 | 6135 | } |
6010 | 6136 | |
6011 | 6137 | static void general_invoke_callback(int decode_args_from_libffi, |
6055 | 6181 | goto error; |
6056 | 6182 | if (convert_from_object_fficallback(result, SIGNATURE(1), py_res, |
6057 | 6183 | decode_args_from_libffi) < 0) { |
6184 | #ifdef USE_WRITEUNRAISABLEMSG | |
6185 | extra_error_line = ", trying to convert the result back to C"; | |
6186 | #else | |
6058 | 6187 | extra_error_line = "Trying to convert the result back to C:\n"; |
6188 | #endif | |
6059 | 6189 | goto error; |
6060 | 6190 | } |
6061 | 6191 | done: |
6107 | 6237 | _my_PyErr_WriteUnraisable(exc1, val1, tb1, |
6108 | 6238 | "From cffi callback ", py_ob, |
6109 | 6239 | extra_error_line); |
6240 | #ifdef USE_WRITEUNRAISABLEMSG | |
6241 | _my_PyErr_WriteUnraisable(exc2, val2, tb2, | |
6242 | "during handling of the above exception by 'onerror'", | |
6243 | NULL, NULL); | |
6244 | #else | |
6110 | 6245 | extra_error_line = ("\nDuring the call to 'onerror', " |
6111 | 6246 | "another exception occurred:\n\n"); |
6112 | 6247 | _my_PyErr_WriteUnraisable(exc2, val2, tb2, |
6113 | 6248 | NULL, NULL, extra_error_line); |
6249 | #endif | |
6114 | 6250 | _cffi_stop_error_capture(ecap); |
6115 | 6251 | } |
6116 | 6252 | } |
6178 | 6314 | infotuple = Py_BuildValue("OOOO", ct, ob, py_rawerr, onerror_ob); |
6179 | 6315 | Py_DECREF(py_rawerr); |
6180 | 6316 | |
6181 | #ifdef WITH_THREAD | |
6317 | #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x03070000 | |
6182 | 6318 | /* We must setup the GIL here, in case the callback is invoked in |
6183 | some other non-Pythonic thread. This is the same as ctypes. */ | |
6319 | some other non-Pythonic thread. This is the same as ctypes. | |
6320 | But PyEval_InitThreads() is always a no-op from CPython 3.7 | |
6321 | (the call from ctypes was removed some time later I think). */ | |
6184 | 6322 | PyEval_InitThreads(); |
6185 | 6323 | #endif |
6186 | 6324 | |
6187 | 6325 | return infotuple; |
6188 | 6326 | } |
6189 | 6327 | |
6328 | /* messily try to silence a gcc/clang deprecation warning for | |
6329 | ffi_prep_closure. Don't miss the "pragma pop" after the function. | |
6330 | This is done around the whole function because very old GCCs don't | |
6331 | support it inside a function. */ | |
6332 | #if defined(__clang__) | |
6333 | # pragma clang diagnostic push | |
6334 | # pragma clang diagnostic ignored "-Wdeprecated-declarations" | |
6335 | #elif defined(__GNUC__) | |
6336 | # pragma GCC diagnostic push | |
6337 | # pragma GCC diagnostic ignored "-Wdeprecated-declarations" | |
6338 | #endif | |
6190 | 6339 | static PyObject *b_callback(PyObject *self, PyObject *args) |
6191 | 6340 | { |
6192 | 6341 | CTypeDescrObject *ct; |
6195 | 6344 | PyObject *infotuple; |
6196 | 6345 | cif_description_t *cif_descr; |
6197 | 6346 | ffi_closure *closure; |
6347 | ffi_status status; | |
6198 | 6348 | void *closure_exec; |
6199 | 6349 | |
6200 | 6350 | if (!PyArg_ParseTuple(args, "O!O|OO:callback", &CTypeDescr_Type, &ct, &ob, |
6205 | 6355 | if (infotuple == NULL) |
6206 | 6356 | return NULL; |
6207 | 6357 | |
6208 | #ifdef CFFI_TRUST_LIBFFI | |
6209 | closure = ffi_closure_alloc(sizeof(ffi_closure), &closure_exec); | |
6210 | #else | |
6211 | closure = cffi_closure_alloc(); | |
6212 | closure_exec = closure; | |
6358 | #if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE | |
6359 | if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { | |
6360 | closure = ffi_closure_alloc(sizeof(ffi_closure), &closure_exec); | |
6361 | } else | |
6213 | 6362 | #endif |
6363 | { | |
6364 | closure = cffi_closure_alloc(); | |
6365 | closure_exec = closure; | |
6366 | } | |
6367 | ||
6214 | 6368 | if (closure == NULL) { |
6215 | 6369 | Py_DECREF(infotuple); |
6216 | 6370 | PyErr_SetString(PyExc_MemoryError, |
6227 | 6381 | cd->head.c_type = ct; |
6228 | 6382 | cd->head.c_data = (char *)closure_exec; |
6229 | 6383 | cd->head.c_weakreflist = NULL; |
6384 | closure->user_data = NULL; | |
6230 | 6385 | cd->closure = closure; |
6231 | PyObject_GC_Track(cd); | |
6232 | 6386 | |
6233 | 6387 | cif_descr = (cif_description_t *)ct->ct_extra; |
6234 | 6388 | if (cif_descr == NULL) { |
6237 | 6391 | "return type or with '...'", ct->ct_name); |
6238 | 6392 | goto error; |
6239 | 6393 | } |
6240 | #ifdef CFFI_TRUST_LIBFFI | |
6241 | if (ffi_prep_closure_loc(closure, &cif_descr->cif, | |
6242 | invoke_callback, infotuple, closure_exec) != FFI_OK) { | |
6394 | ||
6395 | #if CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE | |
6396 | if (CFFI_CHECK_FFI_PREP_CLOSURE_LOC) { | |
6397 | status = ffi_prep_closure_loc(closure, &cif_descr->cif, | |
6398 | invoke_callback, infotuple, closure_exec); | |
6399 | } | |
6400 | else | |
6401 | #endif | |
6402 | { | |
6403 | #if defined(__APPLE__) && defined(FFI_AVAILABLE_APPLE) && !FFI_LEGACY_CLOSURE_API | |
6404 | PyErr_Format(PyExc_SystemError, "ffi_prep_closure_loc() is missing"); | |
6405 | goto error; | |
6243 | 6406 | #else |
6244 | if (ffi_prep_closure(closure, &cif_descr->cif, | |
6245 | invoke_callback, infotuple) != FFI_OK) { | |
6407 | status = ffi_prep_closure(closure, &cif_descr->cif, | |
6408 | invoke_callback, infotuple); | |
6246 | 6409 | #endif |
6410 | } | |
6411 | ||
6412 | if (status != FFI_OK) { | |
6247 | 6413 | PyErr_SetString(PyExc_SystemError, |
6248 | 6414 | "libffi failed to build this callback"); |
6249 | 6415 | goto error; |
6250 | 6416 | } |
6417 | ||
6251 | 6418 | if (closure->user_data != infotuple) { |
6252 | 6419 | /* Issue #266. Should not occur, but could, if we are using |
6253 | 6420 | at runtime a version of libffi compiled with a different |
6262 | 6429 | "different from the 'ffi.h' file seen at compile-time)"); |
6263 | 6430 | goto error; |
6264 | 6431 | } |
6432 | PyObject_GC_Track(cd); | |
6265 | 6433 | return (PyObject *)cd; |
6266 | 6434 | |
6267 | 6435 | error: |
6268 | 6436 | closure->user_data = NULL; |
6269 | 6437 | if (cd == NULL) { |
6270 | #ifdef CFFI_TRUST_LIBFFI | |
6271 | ffi_closure_free(closure); | |
6272 | #else | |
6273 | cffi_closure_free(closure); | |
6438 | #if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE | |
6439 | if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { | |
6440 | ffi_closure_free(closure); | |
6441 | } | |
6442 | else | |
6274 | 6443 | #endif |
6444 | cffi_closure_free(closure); | |
6275 | 6445 | } |
6276 | 6446 | else |
6277 | 6447 | Py_DECREF(cd); |
6278 | 6448 | Py_XDECREF(infotuple); |
6279 | 6449 | return NULL; |
6280 | 6450 | } |
6451 | #if defined(__clang__) | |
6452 | # pragma clang diagnostic pop | |
6453 | #elif defined(__GNUC__) | |
6454 | # pragma GCC diagnostic pop | |
6455 | #endif | |
6281 | 6456 | |
6282 | 6457 | static PyObject *b_new_enum_type(PyObject *self, PyObject *args) |
6283 | 6458 | { |
7787 | 7962 | PyObject *m, *v; |
7788 | 7963 | int i; |
7789 | 7964 | static char init_done = 0; |
7965 | static PyTypeObject *all_types[] = { | |
7966 | &dl_type, | |
7967 | &CTypeDescr_Type, | |
7968 | &CField_Type, | |
7969 | &CData_Type, | |
7970 | &CDataOwning_Type, | |
7971 | &CDataOwningGC_Type, | |
7972 | &CDataFromBuf_Type, | |
7973 | &CDataGCP_Type, | |
7974 | &CDataIter_Type, | |
7975 | &MiniBuffer_Type, | |
7976 | &FFI_Type, | |
7977 | &Lib_Type, | |
7978 | &GlobSupport_Type, | |
7979 | NULL | |
7980 | }; | |
7790 | 7981 | |
7791 | 7982 | v = PySys_GetObject("version"); |
7792 | 7983 | if (v == NULL || !PyText_Check(v) || |
7812 | 8003 | INITERROR; |
7813 | 8004 | } |
7814 | 8005 | |
7815 | if (PyType_Ready(&dl_type) < 0) | |
7816 | INITERROR; | |
7817 | if (PyType_Ready(&CTypeDescr_Type) < 0) | |
7818 | INITERROR; | |
7819 | if (PyType_Ready(&CField_Type) < 0) | |
7820 | INITERROR; | |
7821 | if (PyType_Ready(&CData_Type) < 0) | |
7822 | INITERROR; | |
7823 | if (PyType_Ready(&CDataOwning_Type) < 0) | |
7824 | INITERROR; | |
7825 | if (PyType_Ready(&CDataOwningGC_Type) < 0) | |
7826 | INITERROR; | |
7827 | if (PyType_Ready(&CDataFromBuf_Type) < 0) | |
7828 | INITERROR; | |
7829 | if (PyType_Ready(&CDataGCP_Type) < 0) | |
7830 | INITERROR; | |
7831 | if (PyType_Ready(&CDataIter_Type) < 0) | |
7832 | INITERROR; | |
7833 | if (PyType_Ready(&MiniBuffer_Type) < 0) | |
7834 | INITERROR; | |
8006 | /* readify all types and add them to the module */ | |
8007 | for (i = 0; all_types[i] != NULL; i++) { | |
8008 | PyTypeObject *tp = all_types[i]; | |
8009 | PyObject *tpo = (PyObject *)tp; | |
8010 | if (strncmp(tp->tp_name, "_cffi_backend.", 14) != 0) { | |
8011 | PyErr_Format(PyExc_ImportError, | |
8012 | "'%s' is an ill-formed type name", tp->tp_name); | |
8013 | INITERROR; | |
8014 | } | |
8015 | if (PyType_Ready(tp) < 0) | |
8016 | INITERROR; | |
8017 | ||
8018 | Py_INCREF(tpo); | |
8019 | if (PyModule_AddObject(m, tp->tp_name + 14, tpo) < 0) | |
8020 | INITERROR; | |
8021 | } | |
7835 | 8022 | |
7836 | 8023 | if (!init_done) { |
7837 | 8024 | v = PyText_FromString("_cffi_backend"); |
7877 | 8064 | INITERROR; |
7878 | 8065 | } |
7879 | 8066 | |
7880 | Py_INCREF(&MiniBuffer_Type); | |
7881 | if (PyModule_AddObject(m, "buffer", (PyObject *)&MiniBuffer_Type) < 0) | |
7882 | INITERROR; | |
7883 | ||
7884 | 8067 | init_cffi_tls(); |
7885 | 8068 | if (PyErr_Occurred()) |
7886 | 8069 | INITERROR; |
24 | 24 | PyObject *x; |
25 | 25 | int i, res; |
26 | 26 | static char init_done = 0; |
27 | ||
28 | if (PyType_Ready(&FFI_Type) < 0) | |
29 | return -1; | |
30 | if (PyType_Ready(&Lib_Type) < 0) | |
31 | return -1; | |
32 | 27 | |
33 | 28 | if (!init_done) { |
34 | 29 | if (init_global_types_dict(FFI_Type.tp_dict) < 0) |
61 | 56 | } |
62 | 57 | init_done = 1; |
63 | 58 | } |
64 | ||
65 | x = (PyObject *)&FFI_Type; | |
66 | Py_INCREF(x); | |
67 | if (PyModule_AddObject(m, "FFI", x) < 0) | |
68 | return -1; | |
69 | x = (PyObject *)&Lib_Type; | |
70 | Py_INCREF(x); | |
71 | if (PyModule_AddObject(m, "Lib", x) < 0) | |
72 | return -1; | |
73 | ||
74 | 59 | return 0; |
75 | 60 | } |
76 | 61 |
19 | 19 | |
20 | 20 | static PyTypeObject GlobSupport_Type = { |
21 | 21 | PyVarObject_HEAD_INIT(NULL, 0) |
22 | "FFIGlobSupport", | |
22 | "_cffi_backend.__FFIGlobSupport", | |
23 | 23 | sizeof(GlobSupportObject), |
24 | 24 | 0, |
25 | 25 | (destructor)glob_support_dealloc, /* tp_dealloc */ |
1069 | 1069 | if (res != NULL) { |
1070 | 1070 | tup = PyTuple_Pack(2, Py_True, res); |
1071 | 1071 | if (tup == NULL || PyDict_SetItem(cache, tag, tup) < 0) { |
1072 | Py_XDECREF(tup); | |
1073 | 1072 | Py_DECREF(res); |
1074 | 1073 | res = NULL; |
1075 | 1074 | } |
1075 | Py_XDECREF(tup); | |
1076 | 1076 | } |
1077 | 1077 | } |
1078 | 1078 | |
1136 | 1136 | |
1137 | 1137 | static PyTypeObject FFI_Type = { |
1138 | 1138 | PyVarObject_HEAD_INIT(NULL, 0) |
1139 | "CompiledFFI", | |
1139 | "_cffi_backend.FFI", | |
1140 | 1140 | sizeof(FFIObject), |
1141 | 1141 | 0, |
1142 | 1142 | (destructor)ffi_dealloc, /* tp_dealloc */ |
588 | 588 | |
589 | 589 | static PyTypeObject Lib_Type = { |
590 | 590 | PyVarObject_HEAD_INIT(NULL, 0) |
591 | "CompiledLib", | |
591 | "_cffi_backend.Lib", | |
592 | 592 | sizeof(LibObject), |
593 | 593 | 0, |
594 | 594 | (destructor)lib_dealloc, /* tp_dealloc */ |
102 | 102 | } |
103 | 103 | } |
104 | 104 | #ifdef _WIN64 |
105 | else if (z > 8) | |
105 | else if (z != 1 && z != 2 && z != 4 && z != 8) | |
106 | 106 | { |
107 | 107 | /* On Win64, if a single argument takes more than 8 bytes, |
108 | 108 | then it is always passed by reference. */ |
143 | 143 | /* MSVC returns small structures in registers. Put in cif->flags |
144 | 144 | the value FFI_TYPE_STRUCT only if the structure is big enough; |
145 | 145 | otherwise, put the 4- or 8-bytes integer type. */ |
146 | if (cif->rtype->size <= 4) | |
146 | if (cif->rtype->size == 1 || | |
147 | cif->rtype->size == 2 || | |
148 | cif->rtype->size == 4) | |
147 | 149 | cif->flags = FFI_TYPE_INT; |
148 | else if (cif->rtype->size <= 8) | |
150 | else if (cif->rtype->size == 8) | |
149 | 151 | cif->flags = FFI_TYPE_SINT64; |
150 | 152 | else |
151 | 153 | cif->flags = FFI_TYPE_STRUCT; |
286 | 288 | _asm fld DWORD PTR [eax] ; |
287 | 289 | // asm ("flds (%0)" : : "r" (resp) : "st" ); |
288 | 290 | } |
289 | else if (rtype == FFI_TYPE_DOUBLE) | |
291 | else if (rtype == FFI_TYPE_DOUBLE || rtype == FFI_TYPE_LONGDOUBLE) | |
290 | 292 | { |
291 | 293 | _asm mov eax, resp ; |
292 | 294 | _asm fld QWORD PTR [eax] ; |
293 | 295 | // asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); |
294 | } | |
295 | else if (rtype == FFI_TYPE_LONGDOUBLE) | |
296 | { | |
297 | // asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" ); | |
298 | 296 | } |
299 | 297 | else if (rtype == FFI_TYPE_SINT64) |
300 | 298 | { |
306 | 304 | // : : "r"(resp) |
307 | 305 | // : "eax", "edx"); |
308 | 306 | } |
307 | else if (rtype == FFI_TYPE_STRUCT) | |
308 | { | |
309 | _asm mov eax, resp ; | |
310 | } | |
309 | 311 | #else |
310 | 312 | /* now, do a generic return based on the value of rtype */ |
311 | 313 | if (rtype == FFI_TYPE_INT) |
316 | 318 | { |
317 | 319 | asm ("flds (%0)" : : "r" (resp) : "st" ); |
318 | 320 | } |
319 | else if (rtype == FFI_TYPE_DOUBLE) | |
321 | else if (rtype == FFI_TYPE_DOUBLE || rtype == FFI_TYPE_LONGDOUBLE) | |
320 | 322 | { |
321 | 323 | asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); |
322 | } | |
323 | else if (rtype == FFI_TYPE_LONGDOUBLE) | |
324 | { | |
325 | asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" ); | |
326 | 324 | } |
327 | 325 | else if (rtype == FFI_TYPE_SINT64) |
328 | 326 | { |
331 | 329 | : : "r"(resp) |
332 | 330 | : "eax", "edx"); |
333 | 331 | } |
332 | else if (rtype == FFI_TYPE_STRUCT) | |
333 | { | |
334 | asm ("movl %0,%%eax" : : "r" (resp) : "eax"); | |
335 | } | |
334 | 336 | #endif |
335 | 337 | #endif |
336 | 338 | |
339 | 341 | result types except for floats; we have to 'mov xmm0, rax' in the |
340 | 342 | caller to correct this. |
341 | 343 | */ |
344 | if (rtype == FFI_TYPE_STRUCT) | |
345 | return resp; | |
342 | 346 | return *(void **)resp; |
343 | 347 | #endif |
344 | 348 | } |
377 | 381 | /* because we're little endian, this is what it turns into. */ |
378 | 382 | |
379 | 383 | #ifdef _WIN64 |
380 | if (z > 8) | |
384 | if (z != 1 && z != 2 && z != 4 && z != 8) | |
381 | 385 | { |
382 | 386 | /* On Win64, if a single argument takes more than 8 bytes, |
383 | 387 | then it is always passed by reference. */ |
446 | 450 | || cif->arg_types[3]->type == FFI_TYPE_DOUBLE)) |
447 | 451 | mask |= 8; |
448 | 452 | |
453 | /* if we return a non-small struct, then the first argument is a pointer | |
454 | * to the return area, and all real arguments are shifted by one */ | |
455 | if (cif->flags == FFI_TYPE_STRUCT) | |
456 | mask = (mask & ~8) << 1; | |
457 | ||
449 | 458 | /* 41 BB ---- mov r11d,mask */ |
450 | 459 | BYTES("\x41\xBB"); INT(mask); |
451 | 460 |
116 | 116 | /* Make space for the return structure pointer */ |
117 | 117 | if (cif->rtype->type == FFI_TYPE_STRUCT |
118 | 118 | #ifdef _WIN32 |
119 | && (cif->rtype->size > 8) /* MSVC returns small structs in registers */ | |
119 | && (cif->rtype->size != 1) /* MSVC returns small structs in registers */ | |
120 | && (cif->rtype->size != 2) | |
121 | && (cif->rtype->size != 4) | |
122 | && (cif->rtype->size != 8) | |
120 | 123 | #endif |
121 | 124 | #ifdef SPARC |
122 | 125 | && (cif->abi != FFI_V9 || cif->rtype->size > 32) |
2 | 2 | |
3 | 3 | def _setup_path(): |
4 | 4 | import os, sys |
5 | if '__pypy__' in sys.builtin_module_names: | |
6 | py.test.skip("_cffi_backend.c: not tested on top of pypy, " | |
7 | "use pypy/module/_cffi_backend/test/ instead.") | |
8 | 5 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) |
9 | 6 | _setup_path() |
10 | 7 | from _cffi_backend import * |
11 | from _cffi_backend import _testfunc, _get_types, _get_common_types, __version__ | |
8 | from _cffi_backend import _get_types, _get_common_types | |
9 | try: | |
10 | from _cffi_backend import _testfunc | |
11 | except ImportError: | |
12 | def _testfunc(num): | |
13 | pytest.skip("_testunc() not available") | |
14 | from _cffi_backend import __version__ | |
12 | 15 | |
13 | 16 | # ____________________________________________________________ |
14 | 17 | |
15 | 18 | import sys |
16 | assert __version__ == "1.14.0", ("This test_c.py file is for testing a version" | |
19 | assert __version__ == "1.14.6", ("This test_c.py file is for testing a version" | |
17 | 20 | " of cffi that differs from the one that we" |
18 | 21 | " get from 'import _cffi_backend'") |
19 | 22 | if sys.version_info < (3,): |
64 | 67 | path = ctypes.util.find_library(name) |
65 | 68 | if path is None and name == 'c': |
66 | 69 | assert sys.platform == 'win32' |
67 | assert sys.version_info >= (3,) | |
68 | py.test.skip("dlopen(None) cannot work on Windows with Python 3") | |
70 | assert (sys.version_info >= (3,) or | |
71 | '__pypy__' in sys.builtin_module_names) | |
72 | py.test.skip("dlopen(None) cannot work on Windows " | |
73 | "with PyPy or Python 3") | |
69 | 74 | return load_library(path, flags) |
70 | 75 | |
71 | 76 | def test_load_library(): |
108 | 113 | p = new_primitive_type("signed char") |
109 | 114 | x = cast(p, -65 + 17*256) |
110 | 115 | assert repr(x) == "<cdata 'signed char' -65>" |
111 | assert repr(type(x)) == "<%s '_cffi_backend.CData'>" % type_or_class | |
116 | assert repr(type(x)) == "<%s '_cffi_backend._CDataBase'>" % type_or_class | |
112 | 117 | assert int(x) == -65 |
113 | 118 | x = cast(p, -66 + (1<<199)*256) |
114 | 119 | assert repr(x) == "<cdata 'signed char' -66>" |
1325 | 1330 | except ImportError: |
1326 | 1331 | import io as cStringIO # Python 3 |
1327 | 1332 | import linecache |
1328 | def matches(istr, ipattern): | |
1333 | def matches(istr, ipattern, ipattern38): | |
1334 | if sys.version_info >= (3, 8): | |
1335 | ipattern = ipattern38 | |
1329 | 1336 | str, pattern = istr, ipattern |
1330 | 1337 | while '$' in pattern: |
1331 | 1338 | i = pattern.index('$') |
1358 | 1365 | try: |
1359 | 1366 | linecache.getline = lambda *args: 'LINE' # hack: speed up PyPy tests |
1360 | 1367 | sys.stderr = cStringIO.StringIO() |
1368 | if hasattr(sys, '__unraisablehook__'): # work around pytest | |
1369 | sys.unraisablehook = sys.__unraisablehook__ # on recent CPythons | |
1361 | 1370 | assert f(100) == 300 |
1362 | 1371 | assert sys.stderr.getvalue() == '' |
1363 | 1372 | assert f(10000) == -42 |
1364 | 1373 | assert matches(sys.stderr.getvalue(), """\ |
1365 | 1374 | From cffi callback <function$Zcb1 at 0x$>: |
1375 | Traceback (most recent call last): | |
1376 | File "$", line $, in Zcb1 | |
1377 | $ | |
1378 | File "$", line $, in check_value | |
1379 | $ | |
1380 | ValueError: 42 | |
1381 | """, """\ | |
1382 | Exception ignored from cffi callback <function$Zcb1 at 0x$>: | |
1366 | 1383 | Traceback (most recent call last): |
1367 | 1384 | File "$", line $, in Zcb1 |
1368 | 1385 | $ |
1376 | 1393 | assert matches(sys.stderr.getvalue(), """\ |
1377 | 1394 | From cffi callback <function$Zcb1 at 0x$>: |
1378 | 1395 | Trying to convert the result back to C: |
1396 | OverflowError: integer 60000 does not fit 'short' | |
1397 | """, """\ | |
1398 | Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C: | |
1399 | Traceback (most recent call last): | |
1400 | File "$", line $, in test_callback_exception | |
1401 | $ | |
1379 | 1402 | OverflowError: integer 60000 does not fit 'short' |
1380 | 1403 | """) |
1381 | 1404 | sys.stderr = cStringIO.StringIO() |
1414 | 1437 | During the call to 'onerror', another exception occurred: |
1415 | 1438 | |
1416 | 1439 | TypeError: $integer$ |
1440 | """, """\ | |
1441 | Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C: | |
1442 | Traceback (most recent call last): | |
1443 | File "$", line $, in test_callback_exception | |
1444 | $ | |
1445 | OverflowError: integer 60000 does not fit 'short' | |
1446 | Exception ignored during handling of the above exception by 'onerror': | |
1447 | Traceback (most recent call last): | |
1448 | File "$", line $, in test_callback_exception | |
1449 | $ | |
1450 | TypeError: $integer$ | |
1417 | 1451 | """) |
1418 | 1452 | # |
1419 | 1453 | sys.stderr = cStringIO.StringIO() |
1420 | 1454 | seen = "not a list" # this makes the oops() function crash |
1421 | 1455 | assert ff(bigvalue) == -42 |
1456 | # the $ after the AttributeError message are for the suggestions that | |
1457 | # will be added in Python 3.10 | |
1422 | 1458 | assert matches(sys.stderr.getvalue(), """\ |
1423 | 1459 | From cffi callback <function$Zcb1 at 0x$>: |
1424 | 1460 | Trying to convert the result back to C: |
1429 | 1465 | Traceback (most recent call last): |
1430 | 1466 | File "$", line $, in oops |
1431 | 1467 | $ |
1432 | AttributeError: 'str' object has no attribute 'append' | |
1468 | AttributeError: 'str' object has no attribute 'append$ | |
1469 | """, """\ | |
1470 | Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C: | |
1471 | Traceback (most recent call last): | |
1472 | File "$", line $, in test_callback_exception | |
1473 | $ | |
1474 | OverflowError: integer 60000 does not fit 'short' | |
1475 | Exception ignored during handling of the above exception by 'onerror': | |
1476 | Traceback (most recent call last): | |
1477 | File "$", line $, in oops | |
1478 | $ | |
1479 | AttributeError: 'str' object has no attribute 'append$ | |
1433 | 1480 | """) |
1434 | 1481 | finally: |
1435 | 1482 | sys.stderr = orig_stderr |
1464 | 1511 | def make_callback(m): |
1465 | 1512 | def cb(n): |
1466 | 1513 | return n + m |
1467 | return callback(BFunc, cb, 42) # 'cb' and 'BFunc' go out of scope | |
1514 | return callback(BFunc, cb, 42) # 'cb' goes out of scope | |
1468 | 1515 | # |
1469 | 1516 | flist = [make_callback(i) for i in range(BIGNUM)] |
1470 | 1517 | for i, f in enumerate(flist): |
2547 | 2594 | assert get_errno() == 95 |
2548 | 2595 | |
2549 | 2596 | def test_errno_callback(): |
2550 | if globals().get('PY_DOT_PY') == '2.5': | |
2551 | py.test.skip("cannot run this test on py.py with Python 2.5") | |
2597 | if globals().get('PY_DOT_PY'): | |
2598 | py.test.skip("cannot run this test on py.py (e.g. fails on Windows)") | |
2552 | 2599 | set_errno(95) |
2553 | 2600 | def cb(): |
2554 | 2601 | e = get_errno() |
3967 | 4014 | pv = from_buffer(BVarStructP, bytestring) # make a fresh one |
3968 | 4015 | with pytest.raises(ValueError): |
3969 | 4016 | release(pv[0]) |
4017 | ||
4018 | def test_issue483(): | |
4019 | BInt = new_primitive_type("int") | |
4020 | BIntP = new_pointer_type(BInt) | |
4021 | BIntA = new_array_type(BIntP, None) | |
4022 | lst = list(range(25)) | |
4023 | bytestring = bytearray(buffer(newp(BIntA, lst))[:] + b'XYZ') | |
4024 | p1 = from_buffer(BIntA, bytestring) # int[] | |
4025 | assert len(buffer(p1)) == 25 * size_of_int() | |
4026 | assert sizeof(p1) == 25 * size_of_int() | |
4027 | # | |
4028 | p2 = from_buffer(BIntP, bytestring) | |
4029 | assert sizeof(p2) == size_of_ptr() | |
4030 | assert len(buffer(p2)) == size_of_int() # first element only, by default | |
3970 | 4031 | |
3971 | 4032 | def test_memmove(): |
3972 | 4033 | Short = new_primitive_type("short") |
4452 | 4513 | BStruct = new_struct_type("struct foo") |
4453 | 4514 | complete_struct_or_union(BStruct, [('a1', BArray, -1)]) |
4454 | 4515 | assert sizeof(BStruct) == sys.maxsize |
4516 | ||
4517 | def test_get_types(): | |
4518 | import _cffi_backend | |
4519 | CData, CType = _get_types() | |
4520 | assert CData is _cffi_backend._CDataBase | |
4521 | assert CType is _cffi_backend.CType | |
4522 | ||
4523 | def test_type_available_with_correct_names(): | |
4524 | import _cffi_backend | |
4525 | check_names = [ | |
4526 | 'CType', | |
4527 | 'CField', | |
4528 | 'CLibrary', | |
4529 | '_CDataBase', | |
4530 | 'FFI', | |
4531 | 'Lib', | |
4532 | 'buffer', | |
4533 | ] | |
4534 | if '__pypy__' in sys.builtin_module_names: | |
4535 | check_names += [ | |
4536 | '__CData_iterator', | |
4537 | '__FFIGlobSupport', | |
4538 | '__FFIAllocator', | |
4539 | '__FFIFunctionWrapper', | |
4540 | ] | |
4541 | else: | |
4542 | check_names += [ | |
4543 | '__CDataOwn', | |
4544 | '__CDataOwnGC', | |
4545 | '__CDataFromBuf', | |
4546 | '__CDataGCP', | |
4547 | '__CData_iterator', | |
4548 | '__FFIGlobSupport', | |
4549 | ] | |
4550 | for name in check_names: | |
4551 | tp = getattr(_cffi_backend, name) | |
4552 | assert isinstance(tp, type) | |
4553 | assert (tp.__module__, tp.__name__) == ('_cffi_backend', name) | |
4554 | ||
4555 | def test_unaligned_types(): | |
4556 | BByteArray = new_array_type( | |
4557 | new_pointer_type(new_primitive_type("unsigned char")), None) | |
4558 | pbuf = newp(BByteArray, 40) | |
4559 | buf = buffer(pbuf) | |
4560 | # | |
4561 | for name in ['short', 'int', 'long', 'long long', 'float', 'double', | |
4562 | 'float _Complex', 'double _Complex']: | |
4563 | p = new_primitive_type(name) | |
4564 | if name.endswith(' _Complex'): | |
4565 | num = cast(p, 1.23 - 4.56j) | |
4566 | else: | |
4567 | num = cast(p, 0x0123456789abcdef) | |
4568 | size = sizeof(p) | |
4569 | buf[0:40] = b"\x00" * 40 | |
4570 | pbuf1 = cast(new_pointer_type(p), pbuf + 1) | |
4571 | pbuf1[0] = num | |
4572 | assert pbuf1[0] == num | |
4573 | assert buf[0] == b'\x00' | |
4574 | assert buf[1 + size] == b'\x00' |
4 | 4 | from .error import CDefError, FFIError, VerificationError, VerificationMissing |
5 | 5 | from .error import PkgConfigError |
6 | 6 | |
7 | __version__ = "1.14.0" | |
8 | __version_info__ = (1, 14, 0) | |
7 | __version__ = "1.14.6" | |
8 | __version_info__ = (1, 14, 6) | |
9 | 9 | |
10 | 10 | # The verifier module file names are based on the CRC32 of a string that |
11 | 11 | # contains the following version number. It may be older than __version__ |
53 | 53 | " of.write(x)\n" |
54 | 54 | " except: pass\n" |
55 | 55 | " self.buf += x\n" |
56 | " def flush(self):\n" | |
57 | " pass\n" | |
56 | 58 | "fl = FileLike()\n" |
57 | 59 | "fl.buf = ''\n" |
58 | 60 | "of = sys.stderr\n" |
7 | 7 | the same works for the other two macros. Py_DEBUG implies them, |
8 | 8 | but not the other way around. |
9 | 9 | |
10 | Issue #350 is still open: on Windows, the code here causes it to link | |
11 | with PYTHON36.DLL (for example) instead of PYTHON3.DLL. A fix was | |
12 | attempted in 164e526a5515 and 14ce6985e1c3, but reverted: virtualenv | |
13 | does not make PYTHON3.DLL available, and so the "correctly" compiled | |
14 | version would not run inside a virtualenv. We will re-apply the fix | |
15 | after virtualenv has been fixed for some time. For explanation, see | |
16 | issue #355. For a workaround if you want PYTHON3.DLL and don't worry | |
17 | about virtualenv, see issue #350. See also 'py_limited_api' in | |
18 | setuptools_ext.py. | |
10 | The implementation is messy (issue #350): on Windows, with _MSC_VER, | |
11 | we have to define Py_LIMITED_API even before including pyconfig.h. | |
12 | In that case, we guess what pyconfig.h will do to the macros above, | |
13 | and check our guess after the #include. | |
14 | ||
15 | Note that on Windows, with CPython 3.x, you need >= 3.5 and virtualenv | |
16 | version >= 16.0.0. With older versions of either, you don't get a | |
17 | copy of PYTHON3.DLL in the virtualenv. We can't check the version of | |
18 | CPython *before* we even include pyconfig.h. ffi.set_source() puts | |
19 | a ``#define _CFFI_NO_LIMITED_API'' at the start of this file if it is | |
20 | running on Windows < 3.5, as an attempt at fixing it, but that's | |
21 | arguably wrong because it may not be the target version of Python. | |
22 | Still better than nothing I guess. As another workaround, you can | |
23 | remove the definition of Py_LIMITED_API here. | |
24 | ||
25 | See also 'py_limited_api' in cffi/setuptools_ext.py. | |
19 | 26 | */ |
20 | 27 | #if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API) |
21 | # include <pyconfig.h> | |
22 | # if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) | |
23 | # define Py_LIMITED_API | |
28 | # ifdef _MSC_VER | |
29 | # if !defined(_DEBUG) && !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) | |
30 | # define Py_LIMITED_API | |
31 | # endif | |
32 | # include <pyconfig.h> | |
33 | /* sanity-check: Py_LIMITED_API will cause crashes if any of these | |
34 | are also defined. Normally, the Python file PC/pyconfig.h does not | |
35 | cause any of these to be defined, with the exception that _DEBUG | |
36 | causes Py_DEBUG. Double-check that. */ | |
37 | # ifdef Py_LIMITED_API | |
38 | # if defined(Py_DEBUG) | |
39 | # error "pyconfig.h unexpectedly defines Py_DEBUG, but Py_LIMITED_API is set" | |
40 | # endif | |
41 | # if defined(Py_TRACE_REFS) | |
42 | # error "pyconfig.h unexpectedly defines Py_TRACE_REFS, but Py_LIMITED_API is set" | |
43 | # endif | |
44 | # if defined(Py_REF_DEBUG) | |
45 | # error "pyconfig.h unexpectedly defines Py_REF_DEBUG, but Py_LIMITED_API is set" | |
46 | # endif | |
47 | # endif | |
48 | # else | |
49 | # include <pyconfig.h> | |
50 | # if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) | |
51 | # define Py_LIMITED_API | |
52 | # endif | |
24 | 53 | # endif |
25 | 54 | #endif |
26 | 55 |
223 | 223 | |
224 | 224 | if (f != NULL && f != Py_None) { |
225 | 225 | PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME |
226 | "\ncompiled with cffi version: 1.14.0" | |
226 | "\ncompiled with cffi version: 1.14.6" | |
227 | 227 | "\n_cffi_backend module: ", f); |
228 | 228 | modules = PyImport_GetModuleDict(); |
229 | 229 | mod = PyDict_GetItemString(modules, "_cffi_backend"); |
245 | 245 | goto done; |
246 | 246 | } |
247 | 247 | |
248 | #if PY_VERSION_HEX < 0x03080000 | |
248 | 249 | PyAPI_DATA(char *) _PyParser_TokenNames[]; /* from CPython */ |
250 | #endif | |
249 | 251 | |
250 | 252 | static int _cffi_carefully_make_gil(void) |
251 | 253 | { |
328 | 330 | /* call Py_InitializeEx() */ |
329 | 331 | if (!Py_IsInitialized()) { |
330 | 332 | _cffi_py_initialize(); |
333 | #if PY_VERSION_HEX < 0x03070000 | |
331 | 334 | PyEval_InitThreads(); |
335 | #endif | |
332 | 336 | PyEval_SaveThread(); /* release the GIL */ |
333 | 337 | /* the returned tstate must be the one that has been stored into the |
334 | 338 | autoTLSkey by _PyGILState_Init() called from Py_Initialize(). */ |
335 | 339 | } |
336 | 340 | else { |
341 | #if PY_VERSION_HEX < 0x03070000 | |
342 | /* PyEval_InitThreads() is always a no-op from CPython 3.7 */ | |
337 | 343 | PyGILState_STATE state = PyGILState_Ensure(); |
338 | 344 | PyEval_InitThreads(); |
339 | 345 | PyGILState_Release(state); |
346 | #endif | |
340 | 347 | } |
341 | 348 | |
342 | 349 | #ifdef WITH_THREAD |
360 | 367 | |
361 | 368 | static struct _cffi_pypy_init_s { |
362 | 369 | const char *name; |
363 | void (*func)(const void *[]); | |
370 | void *func; /* function pointer */ | |
364 | 371 | const char *code; |
365 | 372 | } _cffi_pypy_init = { |
366 | 373 | _CFFI_MODULE_NAME, |
367 | (void(*)(const void *[]))_CFFI_PYTHON_STARTUP_FUNC, | |
374 | _CFFI_PYTHON_STARTUP_FUNC, | |
368 | 375 | _CFFI_PYTHON_STARTUP_CODE, |
369 | 376 | }; |
370 | 377 |
28 | 28 | _r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" |
29 | 29 | r"\b((?:[^\n\\]|\\.)*?)$", |
30 | 30 | re.DOTALL | re.MULTILINE) |
31 | _r_line_directive = re.compile(r"^[ \t]*#[ \t]*(?:line|\d+)\b.*$", re.MULTILINE) | |
31 | 32 | _r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}") |
32 | 33 | _r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$") |
33 | 34 | _r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]") |
162 | 163 | "with C it should have a storage class specifier " |
163 | 164 | "(usually 'extern')" % (decl.name,)) |
164 | 165 | |
166 | def _remove_line_directives(csource): | |
167 | # _r_line_directive matches whole lines, without the final \n, if they | |
168 | # start with '#line' with some spacing allowed, or '#NUMBER'. This | |
169 | # function stores them away and replaces them with exactly the string | |
170 | # '#line@N', where N is the index in the list 'line_directives'. | |
171 | line_directives = [] | |
172 | def replace(m): | |
173 | i = len(line_directives) | |
174 | line_directives.append(m.group()) | |
175 | return '#line@%d' % i | |
176 | csource = _r_line_directive.sub(replace, csource) | |
177 | return csource, line_directives | |
178 | ||
179 | def _put_back_line_directives(csource, line_directives): | |
180 | def replace(m): | |
181 | s = m.group() | |
182 | if not s.startswith('#line@'): | |
183 | raise AssertionError("unexpected #line directive " | |
184 | "(should have been processed and removed") | |
185 | return line_directives[int(s[6:])] | |
186 | return _r_line_directive.sub(replace, csource) | |
187 | ||
165 | 188 | def _preprocess(csource): |
189 | # First, remove the lines of the form '#line N "filename"' because | |
190 | # the "filename" part could confuse the rest | |
191 | csource, line_directives = _remove_line_directives(csource) | |
166 | 192 | # Remove comments. NOTE: this only work because the cdef() section |
167 | # should not contain any string literal! | |
168 | csource = _r_comment.sub(' ', csource) | |
193 | # should not contain any string literals (except in line directives)! | |
194 | def replace_keeping_newlines(m): | |
195 | return ' ' + m.group().count('\n') * '\n' | |
196 | csource = _r_comment.sub(replace_keeping_newlines, csource) | |
169 | 197 | # Remove the "#define FOO x" lines |
170 | 198 | macros = {} |
171 | 199 | for match in _r_define.finditer(csource): |
218 | 246 | csource = _r_float_dotdotdot.sub(' __dotdotdotfloat__ ', csource) |
219 | 247 | # Replace all remaining "..." with the same name, "__dotdotdot__", |
220 | 248 | # which is declared with a typedef for the purpose of C parsing. |
221 | return csource.replace('...', ' __dotdotdot__ '), macros | |
249 | csource = csource.replace('...', ' __dotdotdot__ ') | |
250 | # Finally, put back the line directives | |
251 | csource = _put_back_line_directives(csource, line_directives) | |
252 | return csource, macros | |
222 | 253 | |
223 | 254 | def _common_type_names(csource): |
224 | 255 | # Look in the source for what looks like usages of types from the |
394 | 425 | realtype = self._get_unknown_ptr_type(decl) |
395 | 426 | else: |
396 | 427 | realtype, quals = self._get_type_and_quals( |
397 | decl.type, name=decl.name, partial_length_ok=True) | |
428 | decl.type, name=decl.name, partial_length_ok=True, | |
429 | typedef_example="*(%s *)0" % (decl.name,)) | |
398 | 430 | self._declare('typedef ' + decl.name, realtype, quals=quals) |
399 | 431 | elif decl.__class__.__name__ == 'Pragma': |
400 | 432 | pass # skip pragma, only in pycparser 2.15 |
561 | 593 | return model.NamedPointerType(type, declname, quals) |
562 | 594 | return model.PointerType(type, quals) |
563 | 595 | |
564 | def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False): | |
596 | def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False, | |
597 | typedef_example=None): | |
565 | 598 | # first, dereference typedefs, if we have it already parsed, we're good |
566 | 599 | if (isinstance(typenode, pycparser.c_ast.TypeDecl) and |
567 | 600 | isinstance(typenode.type, pycparser.c_ast.IdentifierType) and |
578 | 611 | else: |
579 | 612 | length = self._parse_constant( |
580 | 613 | typenode.dim, partial_length_ok=partial_length_ok) |
614 | # a hack: in 'typedef int foo_t[...][...];', don't use '...' as | |
615 | # the length but use directly the C expression that would be | |
616 | # generated by recompiler.py. This lets the typedef be used in | |
617 | # many more places within recompiler.py | |
618 | if typedef_example is not None: | |
619 | if length == '...': | |
620 | length = '_cffi_array_len(%s)' % (typedef_example,) | |
621 | typedef_example = "*" + typedef_example | |
622 | # | |
581 | 623 | tp, quals = self._get_type_and_quals(typenode.type, |
582 | partial_length_ok=partial_length_ok) | |
624 | partial_length_ok=partial_length_ok, | |
625 | typedef_example=typedef_example) | |
583 | 626 | return model.ArrayType(tp, length), quals |
584 | 627 | # |
585 | 628 | if isinstance(typenode, pycparser.c_ast.PtrDecl): |
306 | 306 | self.c_name_with_marker = ( |
307 | 307 | self.item.c_name_with_marker.replace('&', brackets)) |
308 | 308 | |
309 | def length_is_unknown(self): | |
310 | return isinstance(self.length, str) | |
311 | ||
309 | 312 | def resolve_length(self, newlength): |
310 | 313 | return ArrayType(self.item, newlength) |
311 | 314 | |
312 | 315 | def build_backend_type(self, ffi, finishlist): |
313 | if self.length == '...': | |
316 | if self.length_is_unknown(): | |
314 | 317 | raise CDefError("cannot render the type %r: unknown length" % |
315 | 318 | (self,)) |
316 | 319 | self.item.get_cached_btype(ffi, finishlist) # force the item BType |
429 | 432 | fsize = fieldsize[i] |
430 | 433 | ftype = self.fldtypes[i] |
431 | 434 | # |
432 | if isinstance(ftype, ArrayType) and ftype.length == '...': | |
435 | if isinstance(ftype, ArrayType) and ftype.length_is_unknown(): | |
433 | 436 | # fix the length to match the total size |
434 | 437 | BItemType = ftype.item.get_cached_btype(ffi, finishlist) |
435 | 438 | nlen, nrest = divmod(fsize, ffi.sizeof(BItemType)) |
5 | 5 | VERSION_BASE = 0x2601 |
6 | 6 | VERSION_EMBEDDED = 0x2701 |
7 | 7 | VERSION_CHAR16CHAR32 = 0x2801 |
8 | ||
9 | USE_LIMITED_API = (sys.platform != 'win32' or sys.version_info < (3, 0) or | |
10 | sys.version_info >= (3, 5)) | |
8 | 11 | |
9 | 12 | |
10 | 13 | class GlobalExpr: |
189 | 192 | assert isinstance(op, CffiOp) |
190 | 193 | self.cffi_types = tuple(self.cffi_types) # don't change any more |
191 | 194 | |
195 | def _enum_fields(self, tp): | |
196 | # When producing C, expand all anonymous struct/union fields. | |
197 | # That's necessary to have C code checking the offsets of the | |
198 | # individual fields contained in them. When producing Python, | |
199 | # don't do it and instead write it like it is, with the | |
200 | # corresponding fields having an empty name. Empty names are | |
201 | # recognized at runtime when we import the generated Python | |
202 | # file. | |
203 | expand_anonymous_struct_union = not self.target_is_python | |
204 | return tp.enumfields(expand_anonymous_struct_union) | |
205 | ||
192 | 206 | def _do_collect_type(self, tp): |
193 | 207 | if not isinstance(tp, model.BaseTypeByIdentity): |
194 | 208 | if isinstance(tp, tuple): |
202 | 216 | elif isinstance(tp, model.StructOrUnion): |
203 | 217 | if tp.fldtypes is not None and ( |
204 | 218 | tp not in self.ffi._parser._included_declarations): |
205 | for name1, tp1, _, _ in tp.enumfields(): | |
219 | for name1, tp1, _, _ in self._enum_fields(tp): | |
206 | 220 | self._do_collect_type(self._field_type(tp, name1, tp1)) |
207 | 221 | else: |
208 | 222 | for _, x in tp._get_items(): |
282 | 296 | prnt = self._prnt |
283 | 297 | if self.ffi._embedding is not None: |
284 | 298 | prnt('#define _CFFI_USE_EMBEDDING') |
299 | if not USE_LIMITED_API: | |
300 | prnt('#define _CFFI_NO_LIMITED_API') | |
285 | 301 | # |
286 | 302 | # first the '#include' (actually done by inlining the file's content) |
287 | 303 | lines = self._rel_readlines('_cffi_include.h') |
858 | 874 | prnt('{') |
859 | 875 | prnt(' /* only to generate compile-time warnings or errors */') |
860 | 876 | prnt(' (void)p;') |
861 | for fname, ftype, fbitsize, fqual in tp.enumfields(): | |
877 | for fname, ftype, fbitsize, fqual in self._enum_fields(tp): | |
862 | 878 | try: |
863 | 879 | if ftype.is_integer_type() or fbitsize >= 0: |
864 | 880 | # accept all integers, but complain on float or double |
914 | 930 | flags = '|'.join(flags) or '0' |
915 | 931 | c_fields = [] |
916 | 932 | if reason_for_not_expanding is None: |
917 | expand_anonymous_struct_union = not self.target_is_python | |
918 | enumfields = list(tp.enumfields(expand_anonymous_struct_union)) | |
933 | enumfields = list(self._enum_fields(tp)) | |
919 | 934 | for fldname, fldtype, fbitsize, fqual in enumfields: |
920 | 935 | fldtype = self._field_type(tp, fldname, fldtype) |
921 | 936 | self._check_not_opaque(fldtype, |
1295 | 1310 | def _print_string_literal_in_array(self, s): |
1296 | 1311 | prnt = self._prnt |
1297 | 1312 | prnt('// # NB. this is not a string because of a size limit in MSVC') |
1313 | if not isinstance(s, bytes): # unicode | |
1314 | s = s.encode('utf-8') # -> bytes | |
1315 | else: | |
1316 | s.decode('utf-8') # got bytes, check for valid utf-8 | |
1317 | try: | |
1318 | s.decode('ascii') | |
1319 | except UnicodeDecodeError: | |
1320 | s = b'# -*- encoding: utf8 -*-\n' + s | |
1298 | 1321 | for line in s.splitlines(True): |
1299 | prnt(('// ' + line).rstrip()) | |
1322 | comment = line | |
1323 | if type('//') is bytes: # python2 | |
1324 | line = map(ord, line) # make a list of integers | |
1325 | else: # python3 | |
1326 | # type(line) is bytes, which enumerates like a list of integers | |
1327 | comment = ascii(comment)[1:-1] | |
1328 | prnt(('// ' + comment).rstrip()) | |
1300 | 1329 | printed_line = '' |
1301 | 1330 | for c in line: |
1302 | 1331 | if len(printed_line) >= 76: |
1303 | 1332 | prnt(printed_line) |
1304 | 1333 | printed_line = '' |
1305 | printed_line += '%d,' % (ord(c),) | |
1334 | printed_line += '%d,' % (c,) | |
1306 | 1335 | prnt(printed_line) |
1307 | 1336 | |
1308 | 1337 | # ---------- |
83 | 83 | |
84 | 84 | On Windows, with CPython <= 3.4, it's better not to use py_limited_api |
85 | 85 | because virtualenv *still* doesn't copy PYTHON3.DLL on these versions. |
86 | For now we'll skip py_limited_api on all Windows versions to avoid an | |
87 | inconsistent mess. | |
86 | Recently (2020) we started shipping only >= 3.5 wheels, though. So | |
87 | we'll give it another try and set py_limited_api on Windows >= 3.5. | |
88 | 88 | """ |
89 | from cffi import recompiler | |
90 | ||
89 | 91 | if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount') |
90 | and sys.platform != 'win32'): | |
92 | and recompiler.USE_LIMITED_API): | |
91 | 93 | import setuptools |
92 | 94 | try: |
93 | 95 | setuptools_major_version = int(setuptools.__version__.partition('.')[0]) |
761 | 761 | if isinstance(tp, model.ArrayType): |
762 | 762 | tp_ptr = model.PointerType(tp.item) |
763 | 763 | self._generate_cpy_const(False, name, tp, vartp=tp_ptr, |
764 | size_too = (tp.length == '...')) | |
764 | size_too = tp.length_is_unknown()) | |
765 | 765 | else: |
766 | 766 | tp_ptr = model.PointerType(tp) |
767 | 767 | self._generate_cpy_const(False, name, tp_ptr, category='var') |
773 | 773 | value = getattr(library, name) |
774 | 774 | if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the |
775 | 775 | # sense that "a=..." is forbidden |
776 | if tp.length == '...': | |
776 | if tp.length_is_unknown(): | |
777 | 777 | assert isinstance(value, tuple) |
778 | 778 | (value, size) = value |
779 | 779 | BItemType = self.ffi._get_cached_btype(tp.item) |
564 | 564 | |
565 | 565 | def _generate_gen_variable_decl(self, tp, name): |
566 | 566 | if isinstance(tp, model.ArrayType): |
567 | if tp.length == '...': | |
567 | if tp.length_is_unknown(): | |
568 | 568 | prnt = self._prnt |
569 | 569 | funcname = '_cffi_sizeof_%s' % (name,) |
570 | 570 | self.export_symbols.append(funcname) |
583 | 583 | def _loaded_gen_variable(self, tp, name, module, library): |
584 | 584 | if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the |
585 | 585 | # sense that "a=..." is forbidden |
586 | if tp.length == '...': | |
586 | if tp.length_is_unknown(): | |
587 | 587 | funcname = '_cffi_sizeof_%s' % (name,) |
588 | 588 | BFunc = self.ffi._typeof_locked('size_t(*)(void)')[0] |
589 | 589 | function = module.load_function(BFunc, funcname) |
49 | 49 | if tag: |
50 | 50 | raise TypeError("can't specify both 'modulename' and 'tag'") |
51 | 51 | else: |
52 | key = '\x00'.join([sys.version[:3], __version_verifier_modules__, | |
52 | key = '\x00'.join(['%d.%d' % sys.version_info[:2], | |
53 | __version_verifier_modules__, | |
53 | 54 | preamble, flattened_kwds] + |
54 | 55 | ffi._cdefsources) |
55 | 56 | if sys.version_info >= (3,): |
0 | Metadata-Version: 1.1 | |
0 | Metadata-Version: 2.1 | |
1 | 1 | Name: cffi |
2 | Version: 1.14.0 | |
2 | Version: 1.14.6 | |
3 | 3 | Summary: Foreign Function Interface for Python calling C code. |
4 | 4 | Home-page: http://cffi.readthedocs.org |
5 | 5 | Author: Armin Rigo, Maciej Fijalkowski |
6 | 6 | Author-email: [email protected] |
7 | 7 | License: MIT |
8 | Description: | |
9 | CFFI | |
10 | ==== | |
11 | ||
12 | Foreign Function Interface for Python calling C code. | |
13 | Please see the `Documentation <http://cffi.readthedocs.org/>`_. | |
14 | ||
15 | Contact | |
16 | ------- | |
17 | ||
18 | `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_ | |
19 | ||
20 | 8 | Platform: UNKNOWN |
21 | 9 | Classifier: Programming Language :: Python |
22 | 10 | Classifier: Programming Language :: Python :: 2 |
31 | 19 | Classifier: Programming Language :: Python :: Implementation :: CPython |
32 | 20 | Classifier: Programming Language :: Python :: Implementation :: PyPy |
33 | 21 | Classifier: License :: OSI Approved :: MIT License |
22 | License-File: LICENSE | |
23 | ||
24 | ||
25 | CFFI | |
26 | ==== | |
27 | ||
28 | Foreign Function Interface for Python calling C code. | |
29 | Please see the `Documentation <http://cffi.readthedocs.org/>`_. | |
30 | ||
31 | Contact | |
32 | ------- | |
33 | ||
34 | `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_ | |
35 | ||
36 |
153 | 153 | testing/cffi1/test_dlopen.py |
154 | 154 | testing/cffi1/test_dlopen_unicode_literals.py |
155 | 155 | testing/cffi1/test_ffi_obj.py |
156 | testing/cffi1/test_function_args.py | |
156 | 157 | testing/cffi1/test_new_ffi_1.py |
157 | 158 | testing/cffi1/test_parse_c_type.py |
158 | 159 | testing/cffi1/test_pkgconfig.py |
184 | 185 | testing/embedding/thread2-test.c |
185 | 186 | testing/embedding/thread3-test.c |
186 | 187 | testing/embedding/tlocal-test.c |
187 | testing/embedding/tlocal.py⏎ | |
188 | testing/embedding/tlocal.py | |
189 | testing/embedding/withunicode.py⏎ |
0 | python-cffi-py2 (1.14.6-0kali1) UNRELEASED; urgency=low | |
1 | ||
2 | * New upstream release. | |
3 | ||
4 | -- Kali Janitor <[email protected]> Sat, 21 Aug 2021 10:04:17 -0000 | |
5 | ||
0 | 6 | python-cffi-py2 (1.14.0-2kali2) kali-dev; urgency=medium |
1 | 7 | |
2 | 8 | * Complete debian/copyright |
589 | 589 | different declarations). The reason for that is detailed in `a comment |
590 | 590 | about an issue.`__ |
591 | 591 | |
592 | .. __: https://bitbucket.org/cffi/cffi/issues/265/cffi-doesnt-allow-creating-pointers-to#comment-28406958 | |
592 | .. __: https://foss.heptapod.net/pypy/cffi/-/issues/265#note_50393 | |
593 | 593 | |
594 | 594 | |
595 | 595 | ffibuilder.compile() etc.: compiling out-of-line modules |
46 | 46 | # The short X.Y version. |
47 | 47 | version = '1.14' |
48 | 48 | # The full version, including alpha/beta/rc tags. |
49 | release = '1.14.0' | |
49 | release = '1.14.6' | |
50 | 50 | |
51 | 51 | # The language for content autogenerated by Sphinx. Refer to documentation |
52 | 52 | # for a list of supported languages. |
379 | 379 | ``dlopen("libpythonX.Y.so", RTLD_LAZY|RTLD_GLOBAL)``, which will |
380 | 380 | force ``libpythonX.Y.so`` to be loaded first. |
381 | 381 | |
382 | .. __: https://bitbucket.org/cffi/cffi/issues/264/ | |
382 | .. __: https://foss.heptapod.net/pypy/cffi/-/issues/264 | |
383 | 383 | |
384 | 384 | |
385 | 385 | Using multiple CFFI-made DLLs |
54 | 54 | Comments and bugs |
55 | 55 | ----------------- |
56 | 56 | |
57 | The best way to contact us is on the IRC ``#pypy`` channel of | |
58 | ``irc.freenode.net``. Feel free to discuss matters either there or in | |
57 | The best way to contact us is on the IRC ``#cffi`` or ``#pypy`` channels of | |
58 | ``irc.libera.chat``. Feel free to discuss matters either there or in | |
59 | 59 | the `mailing list`_. Please report to the `issue tracker`_ any bugs. |
60 | 60 | |
61 | 61 | As a general rule, when there is a design issue to resolve, we pick the |
64 | 64 | |
65 | 65 | --- the authors, Armin Rigo and Maciej Fijalkowski |
66 | 66 | |
67 | .. _`issue tracker`: https://bitbucket.org/cffi/cffi/issues | |
67 | .. _`issue tracker`: https://foss.heptapod.net/pypy/cffi/issues | |
68 | 68 | .. _`mailing list`: https://groups.google.com/forum/#!forum/python-cffi |
51 | 51 | |
52 | 52 | * https://pypi.python.org/pypi/cffi |
53 | 53 | |
54 | * Checksums of the "source" package version 1.14.0: | |
54 | * Checksums of the "source" package version 1.14.6: | |
55 | 55 | |
56 | 56 | - MD5: ... |
57 | 57 | |
58 | - SHA: ... | |
58 | - SHA1: ... | |
59 | 59 | |
60 | 60 | - SHA256: ... |
61 | 61 | |
62 | * Or grab the most current version from the `Bitbucket page`_: | |
63 | ``hg clone https://bitbucket.org/cffi/cffi`` | |
62 | * Or grab the most current version from the `Heptapod page`_: | |
63 | ``hg clone https://foss.heptapod.net/pypy/cffi`` | |
64 | 64 | |
65 | 65 | * ``python setup.py install`` or ``python setup_base.py install`` |
66 | 66 | (should work out of the box on Linux or Windows; see below for |
67 | `MacOS X`_ or `Windows 64`_.) | |
67 | `MacOS X`_.) | |
68 | 68 | |
69 | 69 | * running the tests: ``py.test c/ testing/`` (if you didn't |
70 | 70 | install cffi yet, you need first ``python setup_base.py build_ext -f |
71 | 71 | -i``) |
72 | 72 | |
73 | .. _`Bitbucket page`: https://bitbucket.org/cffi/cffi | |
73 | .. _`Heptapod page`: https://foss.heptapod.net/pypy/cffi | |
74 | 74 | |
75 | 75 | Demos: |
76 | 76 | |
81 | 81 | ultimate reference is given by the tests, notably |
82 | 82 | `testing/cffi1/test_verify1.py`_ and `testing/cffi0/backend_tests.py`_. |
83 | 83 | |
84 | .. _`demo`: https://bitbucket.org/cffi/cffi/src/default/demo | |
85 | .. _`testing/cffi1/test_verify1.py`: https://bitbucket.org/cffi/cffi/src/default/testing/cffi1/test_verify1.py | |
86 | .. _`testing/cffi0/backend_tests.py`: https://bitbucket.org/cffi/cffi/src/default/testing/cffi0/backend_tests.py | |
84 | .. _`demo`: https://foss.heptapod.net/pypy/cffi/-/tree/branch/default/demo | |
85 | .. _`testing/cffi1/test_verify1.py`: https://foss.heptapod.net/pypy/cffi/-/blob/branch/default/testing/cffi1/test_verify1.py | |
86 | .. _`testing/cffi0/backend_tests.py`: https://foss.heptapod.net/pypy/cffi/-/blob/branch/default/testing/cffi0/backend_tests.py | |
87 | 87 | |
88 | 88 | |
89 | 89 | Platform-specific instructions |
132 | 132 | .. _here: http://superuser.com/questions/259278/python-2-6-1-pycrypto-2-3-pypi-package-broken-pipe-during-build |
133 | 133 | |
134 | 134 | |
135 | Windows (regular 32-bit) | |
136 | ++++++++++++++++++++++++ | |
135 | Windows (32/64-bit) | |
136 | +++++++++++++++++++ | |
137 | 137 | |
138 | Win32 works and is tested at least each official release. | |
138 | Win32 and Win64 work and are tested at least each official release. | |
139 | 139 | |
140 | 140 | The recommended C compiler compatible with Python 2.7 is this one: |
141 | 141 | http://www.microsoft.com/en-us/download/details.aspx?id=44266 |
147 | 147 | |
148 | 148 | For Python 3.4 and beyond: |
149 | 149 | https://www.visualstudio.com/en-us/downloads/visual-studio-2015-ctp-vs |
150 | ||
151 | ||
152 | Windows 64 | |
153 | ++++++++++ | |
154 | ||
155 | Win64 received very basic testing and we applied a few essential | |
156 | fixes in cffi 0.7. The comment above applies for Python 2.7 on | |
157 | Windows 64 as well. Please report any other issue. | |
158 | ||
159 | Note as usual that this is only about running the 64-bit version of | |
160 | Python on the 64-bit OS. If you're running the 32-bit version (the | |
161 | common case apparently), then you're running Win32 as far as we're | |
162 | concerned. | |
163 | ||
164 | .. _`issue 9`: https://bitbucket.org/cffi/cffi/issue/9 | |
165 | .. _`Python issue 7546`: http://bugs.python.org/issue7546 | |
166 | 150 | |
167 | 151 | |
168 | 152 | Linux and OS/X: UCS2 versus UCS4 |
357 | 357 | from _pi.lib import pi_approx |
358 | 358 | |
359 | 359 | approx = pi_approx(10) |
360 | assert str(pi_approximation).startswith("3.") | |
360 | assert str(approx).startswith("3.") | |
361 | 361 | |
362 | 362 | approx = pi_approx(10000) |
363 | 363 | assert str(approx).startswith("3.1") |
458 | 458 | order, see the discussion in `issue 340`__. |
459 | 459 | |
460 | 460 | .. __: http://bugs.python.org/issue31105 |
461 | .. __: https://bitbucket.org/cffi/cffi/issues/340/resources-release-issues | |
461 | .. __: https://foss.heptapod.net/pypy/cffi/-/issues/340 | |
462 | 462 | |
463 | 463 | |
464 | 464 | .. _ffi-new-handle: |
730 | 730 | raise IndexError("index too large!") |
731 | 731 | ... |
732 | 732 | |
733 | .. __: https://bitbucket.org/cffi/cffi/issues/233/ | |
733 | .. __: https://foss.heptapod.net/pypy/cffi/-/issues/233 | |
734 | 734 | |
735 | 735 | |
736 | 736 | .. _ffi-getctype: |
786 | 786 | may be implemented in the future. (`This demo`__ shows how to do it |
787 | 787 | anyway, but it is a bit lengthy.) |
788 | 788 | |
789 | .. __: https://bitbucket.org/cffi/cffi/src/default/demo/extern_python_varargs.py | |
789 | .. __: https://foss.heptapod.net/pypy/cffi/-/blob/branch/default/demo/extern_python_varargs.py | |
790 | 790 | |
791 | 791 | Each corresponding Python callback function is defined with the |
792 | 792 | ``@ffi.def_extern()`` decorator. Be careful when writing this |
895 | 895 | to refactor the involved code so that it no longer uses ``ffi.callback()``. |
896 | 896 | |
897 | 897 | .. __: https://github.com/pyca/pyopenssl/issues/596 |
898 | .. __: https://bitbucket.org/cffi/cffi/issues/391/ | |
898 | .. __: https://foss.heptapod.net/pypy/cffi/-/issues/391 | |
899 | 899 | .. __: https://bugzilla.redhat.com/show_bug.cgi?id=1249685 |
900 | 900 | |
901 | 901 | Warning: like ffi.new(), ffi.callback() returns a cdata that has |
0 | 0 | ====================== |
1 | 1 | What's New |
2 | 2 | ====================== |
3 | ||
4 | v1.14.6 | |
5 | ======= | |
6 | ||
7 | * Test fixes for CPython 3.10.0b3 | |
8 | ||
9 | * Support for `sys.unraisablehook()` on Python >= 3.8 | |
10 | ||
11 | * Fix two minor memory leaks (thanks Sebastian!) | |
12 | ||
13 | * Like many projects that had an IRC channel on freenode, we moved it to | |
14 | ``irc.libera.chat``. | |
15 | ||
16 | v1.14.5 | |
17 | ======= | |
18 | ||
19 | * Source fix for old gcc versions | |
20 | ||
21 | * This and future releases should include wheels on more platforms, | |
22 | thanks to our new release managers Matt and Matt! | |
23 | ||
24 | v1.14.4 | |
25 | ======= | |
26 | ||
27 | Release done for pip reasons. | |
28 | ||
29 | v1.14.3 | |
30 | ======= | |
31 | ||
32 | Release done for pip reasons. | |
33 | ||
34 | v1.14.2 | |
35 | ======= | |
36 | ||
37 | * CPython 3 on Windows: we again try to compile with ``Py_LIMITED_API`` | |
38 | by default. This flag is not added if you run the compilation with | |
39 | CPython 3.4, as it only works with CPython >= 3.5, but by now this | |
40 | version of Python is quite old (and we no longer distribute cffi | |
41 | wheels for it). | |
42 | ||
43 | This may require that you upgrade ``virtualenv`` (requires version 16 | |
44 | or newer) or at least copy manually ``python3.dll`` into your existing | |
45 | virtualenvs. For distributing wheels with your cffi modules, you may | |
46 | also need to upgrade ``wheel`` to the just-released version 0.35. | |
47 | ||
48 | You can manually disable ``Py_LIMITED_API`` by calling | |
49 | ``ffi.set_source(..., py_limited_api=False)``. | |
50 | ||
51 | ||
52 | v1.14.1 | |
53 | ======= | |
54 | ||
55 | * CFFI source code is now `hosted on Heptapod`_. | |
56 | ||
57 | * Improved support for ``typedef int my_array_t[...];`` with an explicit | |
58 | dot-dot-dot in API mode (`issue #453`_) | |
59 | ||
60 | * Windows (32 and 64 bits): multiple fixes for ABI-mode call to functions | |
61 | that return a structure. | |
62 | ||
63 | * Experimental support for MacOS 11 on aarch64. | |
64 | ||
65 | * and a few other minor changes and bug fixes. | |
66 | ||
67 | .. _`hosted on Heptapod`: https://foss.heptapod.net/pypy/cffi/ | |
68 | .. _`issue #453`: https://foss.heptapod.net/pypy/cffi/issues/453 | |
3 | 69 | |
4 | 70 | |
5 | 71 | v1.14 |
35 | 101 | * re-release because the Linux wheels came with an attached version of libffi |
36 | 102 | that was very old and buggy (`issue #432`_). |
37 | 103 | |
38 | .. _`issue #432`: https://bitbucket.org/cffi/cffi/issues/432/ | |
104 | .. _`issue #432`: https://foss.heptapod.net/pypy/cffi/-/issues/432 | |
39 | 105 | |
40 | 106 | |
41 | 107 | |
54 | 120 | * fixed `issue #427`_ where a multithreading mistake in the embedding logic |
55 | 121 | initialization code would cause deadlocks on CPython 3.7. |
56 | 122 | |
57 | .. _`issue #429`: https://bitbucket.org/cffi/cffi/issues/429/ | |
58 | .. _`issue #427`: https://bitbucket.org/cffi/cffi/issues/427/ | |
123 | .. _`issue #429`: https://foss.heptapod.net/pypy/cffi/-/issues/429 | |
124 | .. _`issue #427`: https://foss.heptapod.net/pypy/cffi/-/issues/427 | |
59 | 125 | |
60 | 126 | |
61 | 127 | v1.13 |
81 | 147 | recursion, with ``ffi.cdef("""struct X { void(*fnptr)(struct X); };""")`` |
82 | 148 | |
83 | 149 | |
150 | Older Versions | |
151 | ============== | |
152 | ||
84 | 153 | v1.12.3 |
85 | ======= | |
154 | ------- | |
86 | 155 | |
87 | 156 | * Fix for nested struct types that end in a var-sized array (#405). |
88 | 157 | |
93 | 162 | |
94 | 163 | |
95 | 164 | v1.12.2 |
96 | ======= | |
165 | ------- | |
97 | 166 | |
98 | 167 | * Added temporary workaround to compile on CPython 3.8.0a2. |
99 | 168 | |
100 | 169 | |
101 | 170 | v1.12.1 |
102 | ======= | |
171 | ------- | |
103 | 172 | |
104 | 173 | * CPython 3 on Windows: we again no longer compile with ``Py_LIMITED_API`` |
105 | 174 | by default because such modules *still* cannot be used with virtualenv. |
115 | 184 | |
116 | 185 | |
117 | 186 | v1.12 |
118 | ===== | |
187 | ----- | |
119 | 188 | |
120 | 189 | * `Direct support for pkg-config`__. |
121 | 190 | |
150 | 219 | to 1 byte instead of 4). |
151 | 220 | |
152 | 221 | .. __: cdef.html#pkgconfig |
153 | .. _`issue #362`: https://bitbucket.org/cffi/cffi/issues/362/ | |
154 | ||
155 | ||
156 | Older Versions | |
157 | ============== | |
222 | .. _`issue #362`: https://foss.heptapod.net/pypy/cffi/-/issues/362 | |
223 | ||
158 | 224 | |
159 | 225 | v1.11.5 |
160 | 226 | ------- |
185 | 251 | concerned about virtualenv: pass ``define_macros=[("Py_LIMITED_API", |
186 | 252 | None)]`` as a keyword to the ``ffibuilder.set_source()`` call. |
187 | 253 | |
188 | .. _`Issue #345`: https://bitbucket.org/cffi/cffi/issues/345/ | |
189 | .. _`Issue #350`: https://bitbucket.org/cffi/cffi/issues/350/ | |
190 | .. _`Issue #358`: https://bitbucket.org/cffi/cffi/issues/358/ | |
191 | .. _`Issue #357`: https://bitbucket.org/cffi/cffi/issues/357/ | |
254 | .. _`Issue #345`: https://foss.heptapod.net/pypy/cffi/-/issues/345 | |
255 | .. _`Issue #350`: https://foss.heptapod.net/pypy/cffi/-/issues/350 | |
256 | .. _`Issue #358`: https://foss.heptapod.net/pypy/cffi/-/issues/358 | |
257 | .. _`Issue #357`: https://foss.heptapod.net/pypy/cffi/-/issues/357 | |
192 | 258 | |
193 | 259 | |
194 | 260 | v1.11.4 |
201 | 267 | ``foo.cp36-win32.pyd``, to make it clear that they are regular |
202 | 268 | CPython modules depending on ``python36.dll``. |
203 | 269 | |
204 | .. _`Issue #355`: https://bitbucket.org/cffi/cffi/issues/355/ | |
270 | .. _`Issue #355`: https://foss.heptapod.net/pypy/cffi/-/issues/355 | |
205 | 271 | |
206 | 272 | |
207 | 273 | v1.11.3 |
290 | 356 | that are *slower* to call than the API mode does. For some reason it |
291 | 357 | is often thought to be faster. It is not! |
292 | 358 | |
293 | .. __: https://bitbucket.org/cffi/cffi/issues/321/cffi-191-segmentation-fault-during-self | |
359 | .. __: https://foss.heptapod.net/pypy/cffi/-/issues/321 | |
294 | 360 | .. __: ref.html#ffi-gc |
295 | .. __: https://bitbucket.org/cffi/cffi/issues/320/improve-memory_pressure-management | |
361 | .. __: https://foss.heptapod.net/pypy/cffi/-/issues/320 | |
296 | 362 | .. __: http://bugs.python.org/issue31105 |
297 | 363 | |
298 | 364 |
55 | 55 | tries to compile C code. (Hints: on OS/X 10.8, for errors about |
56 | 56 | -mno-fused-madd see http://stackoverflow.com/questions/22313407/ |
57 | 57 | Otherwise, see https://wiki.python.org/moin/CompLangPython or |
58 | the IRC channel #python on irc.freenode.net.) | |
58 | the IRC channel #python on irc.libera.chat.) | |
59 | 59 | |
60 | 60 | Trying to continue anyway. If you are trying to install CFFI from |
61 | 61 | a build done in a different context, you can ignore this warning. |
148 | 148 | ask_supports_thread() |
149 | 149 | ask_supports_sync_synchronize() |
150 | 150 | |
151 | if 'darwin' in sys.platform: | |
152 | # priority is given to `pkg_config`, but always fall back on SDK's libffi. | |
153 | extra_compile_args += ['-iwithsysroot/usr/include/ffi'] | |
154 | ||
151 | 155 | if 'freebsd' in sys.platform: |
152 | 156 | include_dirs.append('/usr/local/include') |
153 | 157 | library_dirs.append('/usr/local/lib') |
154 | ||
155 | if 'darwin' in sys.platform: | |
156 | try: | |
157 | p = subprocess.Popen(['xcrun', '--show-sdk-path'], | |
158 | stdout=subprocess.PIPE) | |
159 | except OSError as e: | |
160 | if e.errno not in [errno.ENOENT, errno.EACCES]: | |
161 | raise | |
162 | else: | |
163 | t = p.stdout.read().decode().strip() | |
164 | p.stdout.close() | |
165 | if p.wait() == 0: | |
166 | include_dirs.append(t + '/usr/include/ffi') | |
167 | ||
168 | ||
169 | 158 | |
170 | 159 | if __name__ == '__main__': |
171 | 160 | from setuptools import setup, Distribution, Extension |
197 | 186 | |
198 | 187 | `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_ |
199 | 188 | """, |
200 | version='1.14.0', | |
189 | version='1.14.6', | |
201 | 190 | packages=['cffi'] if cpython else [], |
202 | 191 | package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h', |
203 | 192 | '_embedding.h', '_cffi_errors.h']} |
7 | 7 | if __name__ == '__main__': |
8 | 8 | from distutils.core import setup |
9 | 9 | from distutils.extension import Extension |
10 | ||
10 | 11 | standard = '__pypy__' not in sys.builtin_module_names |
11 | 12 | setup(packages=['cffi'], |
12 | 13 | requires=['pycparser'], |
0 | 0 | import py |
1 | 1 | import pytest |
2 | 2 | import platform |
3 | import sys, ctypes | |
3 | import sys, ctypes, ctypes.util | |
4 | 4 | from cffi import FFI, CDefError, FFIError, VerificationMissing |
5 | 5 | from testing.support import * |
6 | 6 | |
11 | 11 | SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar) |
12 | 12 | |
13 | 13 | def needs_dlopen_none(): |
14 | if sys.platform == 'win32' and sys.version_info >= (3,): | |
15 | py.test.skip("dlopen(None) cannot work on Windows for Python 3") | |
14 | if sys.platform == 'win32' and not ctypes.util.find_library('c'): | |
15 | py.test.skip("dlopen(None) cannot work on Windows with this runtime") | |
16 | 16 | |
17 | 17 | |
18 | 18 | class BackendTests: |
178 | 178 | setters = ['case %d: s.%s = value; break;' % iname |
179 | 179 | for iname in enumerate(fnames)] |
180 | 180 | lib = ffi1.verify(""" |
181 | #include <string.h> | |
181 | 182 | struct s1 { %s }; |
182 | 183 | struct sa { char a; struct s1 b; }; |
183 | 184 | #define Gofs_y offsetof(struct s1, y) |
245 | 246 | self.check("int a:2; short b:15; char c:2; char y;", 5, 4, 8) |
246 | 247 | self.check("int a:2; char b:1; char c:1; char y;", 1, 4, 4) |
247 | 248 | |
248 | @pytest.mark.skipif("platform.machine().startswith(('arm', 'aarch64'))") | |
249 | @pytest.mark.skipif( | |
250 | "not (sys.platform == 'darwin' and platform.machine() == 'arm64')" | |
251 | " and " | |
252 | "platform.machine().startswith(('arm', 'aarch64'))") | |
249 | 253 | def test_bitfield_anonymous_no_align(self): |
250 | 254 | L = FFI().alignof("long long") |
251 | 255 | self.check("char y; int :1;", 0, 1, 2) |
259 | 263 | self.check("char x; long long :57; char y;", L + 8, 1, L + 9) |
260 | 264 | |
261 | 265 | @pytest.mark.skipif( |
266 | "(sys.platform == 'darwin' and platform.machine() == 'arm64')" | |
267 | " or " | |
262 | 268 | "not platform.machine().startswith(('arm', 'aarch64'))") |
263 | 269 | def test_bitfield_anonymous_align_arm(self): |
264 | 270 | L = FFI().alignof("long long") |
272 | 278 | self.check("char x; long long z:57; char y;", L + 8, L, L + 8 + L) |
273 | 279 | self.check("char x; long long :57; char y;", L + 8, L, L + 8 + L) |
274 | 280 | |
275 | @pytest.mark.skipif("platform.machine().startswith(('arm', 'aarch64'))") | |
281 | @pytest.mark.skipif( | |
282 | "not (sys.platform == 'darwin' and platform.machine() == 'arm64')" | |
283 | " and " | |
284 | "platform.machine().startswith(('arm', 'aarch64'))") | |
276 | 285 | def test_bitfield_zero(self): |
277 | 286 | L = FFI().alignof("long long") |
278 | 287 | self.check("char y; int :0;", 0, 1, 4) |
284 | 293 | self.check("int a:1; int :0; int b:1; char y;", 5, 4, 8) |
285 | 294 | |
286 | 295 | @pytest.mark.skipif( |
296 | "(sys.platform == 'darwin' and platform.machine() == 'arm64')" | |
297 | " or " | |
287 | 298 | "not platform.machine().startswith(('arm', 'aarch64'))") |
288 | 299 | def test_bitfield_zero_arm(self): |
289 | 300 | L = FFI().alignof("long long") |
4 | 4 | import ctypes.util |
5 | 5 | from cffi.backend_ctypes import CTypesBackend |
6 | 6 | from testing.udir import udir |
7 | from testing.support import FdWriteCapture | |
7 | from testing.support import FdWriteCapture, StdErrCapture | |
8 | 8 | from .backend_tests import needs_dlopen_none |
9 | 9 | |
10 | 10 | try: |
226 | 226 | def cb(): |
227 | 227 | return returnvalue |
228 | 228 | fptr = ffi.callback("void(*)(void)", cb) |
229 | old_stderr = sys.stderr | |
230 | try: | |
231 | sys.stderr = StringIO() | |
229 | with StdErrCapture() as f: | |
232 | 230 | returned = fptr() |
233 | printed = sys.stderr.getvalue() | |
234 | finally: | |
235 | sys.stderr = old_stderr | |
231 | printed = f.getvalue() | |
236 | 232 | assert returned is None |
237 | 233 | if returnvalue is None: |
238 | 234 | assert printed == '' |
239 | 235 | else: |
240 | 236 | assert "None" in printed |
237 | ||
238 | def test_callback_returning_struct_three_bytes(self): | |
239 | if self.Backend is CTypesBackend: | |
240 | py.test.skip("not supported with the ctypes backend") | |
241 | ffi = FFI(backend=self.Backend()) | |
242 | ffi.cdef(""" | |
243 | typedef struct { | |
244 | unsigned char a, b, c; | |
245 | } THREEBYTES; | |
246 | """) | |
247 | def cb(): | |
248 | return (12, 34, 56) | |
249 | fptr = ffi.callback("THREEBYTES(*)(void)", cb) | |
250 | tb = fptr() | |
251 | assert tb.a == 12 | |
252 | assert tb.b == 34 | |
253 | assert tb.c == 56 | |
241 | 254 | |
242 | 255 | def test_passing_array(self): |
243 | 256 | ffi = FFI(backend=self.Backend()) |
33 | 33 | long right; |
34 | 34 | long bottom; |
35 | 35 | } RECT; |
36 | ||
37 | typedef struct { | |
38 | unsigned char a, b, c; | |
39 | } THREEBYTES; | |
36 | 40 | |
37 | 41 | |
38 | 42 | EXPORT int PointInRect(RECT *prc, POINT pt) |
105 | 109 | EXPORT void modify_struct_value(RECT r) |
106 | 110 | { |
107 | 111 | r.left = r.right = r.top = r.bottom = 500; |
112 | } | |
113 | ||
114 | EXPORT THREEBYTES return_three_bytes(void) | |
115 | { | |
116 | THREEBYTES result; | |
117 | result.a = 12; | |
118 | result.b = 34; | |
119 | result.c = 56; | |
120 | return result; | |
108 | 121 | } |
109 | 122 | """ |
110 | 123 | |
396 | 409 | |
397 | 410 | err = lib1.dlclose(handle) |
398 | 411 | assert err == 0 |
412 | ||
413 | def test_return_three_bytes(self): | |
414 | if self.module is None: | |
415 | py.test.skip("fix the auto-generation of the tiny test lib") | |
416 | if self.__class__.Backend is CTypesBackend: | |
417 | py.test.skip("not working on win32 on the ctypes backend") | |
418 | ffi = FFI(backend=self.Backend()) | |
419 | ffi.cdef(""" | |
420 | typedef struct { | |
421 | unsigned char a, b, c; | |
422 | } THREEBYTES; | |
423 | ||
424 | THREEBYTES return_three_bytes(void); | |
425 | """) | |
426 | lib = ffi.dlopen(self.module) | |
427 | tb = lib.return_three_bytes() | |
428 | assert tb.a == 12 | |
429 | assert tb.b == 34 | |
430 | assert tb.c == 56 |
173 | 173 | double // blah \\ |
174 | 174 | more comments |
175 | 175 | x(void); |
176 | double // blah\\\\ | |
176 | double // blah // blah\\\\ | |
177 | 177 | y(void); |
178 | 178 | double // blah\\ \ |
179 | 179 | etc |
183 | 183 | m.x |
184 | 184 | m.y |
185 | 185 | m.z |
186 | ||
187 | def test_dont_remove_comment_in_line_directives(): | |
188 | ffi = FFI(backend=FakeBackend()) | |
189 | e = py.test.raises(CDefError, ffi.cdef, """ | |
190 | \t # \t line \t 8 \t "baz.c" \t | |
191 | ||
192 | some syntax error here | |
193 | """) | |
194 | assert str(e.value) == "parse error\nbaz.c:9:14: before: syntax" | |
195 | # | |
196 | e = py.test.raises(CDefError, ffi.cdef, """ | |
197 | #line 7 "foo//bar.c" | |
198 | ||
199 | some syntax error here | |
200 | """) | |
201 | # | |
202 | assert str(e.value) == "parse error\nfoo//bar.c:8:14: before: syntax" | |
203 | ffi = FFI(backend=FakeBackend()) | |
204 | e = py.test.raises(CDefError, ffi.cdef, """ | |
205 | \t # \t 8 \t "baz.c" \t | |
206 | ||
207 | some syntax error here | |
208 | """) | |
209 | assert str(e.value) == "parse error\nbaz.c:9:14: before: syntax" | |
210 | # | |
211 | e = py.test.raises(CDefError, ffi.cdef, """ | |
212 | # 7 "foo//bar.c" | |
213 | ||
214 | some syntax error here | |
215 | """) | |
216 | assert str(e.value) == "parse error\nfoo//bar.c:8:14: before: syntax" | |
217 | ||
218 | def test_multiple_line_directives(): | |
219 | ffi = FFI(backend=FakeBackend()) | |
220 | e = py.test.raises(CDefError, ffi.cdef, | |
221 | """ #line 5 "foo.c" | |
222 | extern int xx; | |
223 | #line 6 "bar.c" | |
224 | extern int yy; | |
225 | #line 7 "baz.c" | |
226 | some syntax error here | |
227 | #line 8 "yadda.c" | |
228 | extern int zz; | |
229 | """) | |
230 | assert str(e.value) == "parse error\nbaz.c:7:14: before: syntax" | |
231 | # | |
232 | e = py.test.raises(CDefError, ffi.cdef, | |
233 | """ # 5 "foo.c" | |
234 | extern int xx; | |
235 | # 6 "bar.c" | |
236 | extern int yy; | |
237 | # 7 "baz.c" | |
238 | some syntax error here | |
239 | # 8 "yadda.c" | |
240 | extern int zz; | |
241 | """) | |
242 | assert str(e.value) == "parse error\nbaz.c:7:14: before: syntax" | |
243 | ||
244 | def test_commented_line_directive(): | |
245 | ffi = FFI(backend=FakeBackend()) | |
246 | e = py.test.raises(CDefError, ffi.cdef, """ | |
247 | /* | |
248 | #line 5 "foo.c" | |
249 | */ | |
250 | void xx(void); | |
251 | ||
252 | #line 6 "bar.c" | |
253 | /* | |
254 | #line 35 "foo.c" | |
255 | */ | |
256 | some syntax error | |
257 | """) | |
258 | # | |
259 | assert str(e.value) == "parse error\nbar.c:9:14: before: syntax" | |
260 | e = py.test.raises(CDefError, ffi.cdef, """ | |
261 | /* | |
262 | # 5 "foo.c" | |
263 | */ | |
264 | void xx(void); | |
265 | ||
266 | # 6 "bar.c" | |
267 | /* | |
268 | # 35 "foo.c" | |
269 | */ | |
270 | some syntax error | |
271 | """) | |
272 | assert str(e.value) == "parse error\nbar.c:9:14: before: syntax" | |
186 | 273 | |
187 | 274 | def test_line_continuation_in_defines(): |
188 | 275 | ffi = FFI(backend=FakeBackend()) |
35 | 35 | v = cffi.__version__.replace('+', '') |
36 | 36 | p = os.path.join(parent, 'doc', 'source', 'installation.rst') |
37 | 37 | content = open(p).read() |
38 | assert (" package version %s:" % v) in content | |
38 | if " package version %s:" % v not in content: | |
39 | for i in range(5): | |
40 | if " package version %s-%d:" % (v, i) in content: | |
41 | break | |
42 | else: | |
43 | assert 0, "doc/source/installation.rst needs updating" | |
39 | 44 | |
40 | 45 | def test_setup_version(): |
41 | 46 | parent = os.path.dirname(os.path.dirname(cffi.__file__)) |
0 | import pytest, sys | |
1 | try: | |
2 | # comment out the following line to run this test. | |
3 | # the latest on x86-64 linux: https://github.com/libffi/libffi/issues/574 | |
4 | if sys.platform != 'win32': | |
5 | raise ImportError("this test is skipped because it keeps finding " | |
6 | "failures in libffi, instead of cffi") | |
7 | ||
8 | from hypothesis import given, settings, example | |
9 | from hypothesis import strategies as st | |
10 | except ImportError as e: | |
11 | e1 = e | |
12 | def test_types(): | |
13 | pytest.skip(str(e1)) | |
14 | else: | |
15 | ||
16 | from cffi import FFI | |
17 | import sys, random | |
18 | from .test_recompiler import verify | |
19 | ||
20 | ALL_PRIMITIVES = [ | |
21 | 'unsigned char', | |
22 | 'short', | |
23 | 'int', | |
24 | 'long', | |
25 | 'long long', | |
26 | 'float', | |
27 | 'double', | |
28 | #'long double', --- on x86 it can give libffi crashes | |
29 | ] | |
30 | def _make_struct(s): | |
31 | return st.lists(s, min_size=1) | |
32 | types = st.one_of(st.sampled_from(ALL_PRIMITIVES), | |
33 | st.lists(st.sampled_from(ALL_PRIMITIVES), min_size=1)) | |
34 | # NB. 'types' could be st.recursive instead, but it doesn't | |
35 | # really seem useful | |
36 | ||
37 | def draw_primitive(ffi, typename): | |
38 | value = random.random() * 2**40 | |
39 | if typename != 'long double': | |
40 | return ffi.cast(typename, value) | |
41 | else: | |
42 | return value | |
43 | ||
44 | TEST_RUN_COUNTER = 0 | |
45 | ||
46 | ||
47 | @given(st.lists(types), types) | |
48 | @settings(max_examples=100, deadline=5000) # 5000ms | |
49 | def test_types(tp_args, tp_result): | |
50 | global TEST_RUN_COUNTER | |
51 | print(tp_args, tp_result) | |
52 | cdefs = [] | |
53 | structs = {} | |
54 | ||
55 | def build_type(tp): | |
56 | if type(tp) is list: | |
57 | field_types = [build_type(tp1) for tp1 in tp] | |
58 | fields = ['%s f%d;' % (ftp, j) | |
59 | for (j, ftp) in enumerate(field_types)] | |
60 | fields = '\n '.join(fields) | |
61 | name = 's%d' % len(cdefs) | |
62 | cdefs.append("typedef struct {\n %s\n} %s;" % (fields, name)) | |
63 | structs[name] = field_types | |
64 | return name | |
65 | else: | |
66 | return tp | |
67 | ||
68 | args = [build_type(tp) for tp in tp_args] | |
69 | result = build_type(tp_result) | |
70 | ||
71 | TEST_RUN_COUNTER += 1 | |
72 | signature = "%s testfargs(%s)" % (result, | |
73 | ', '.join(['%s a%d' % (arg, i) for (i, arg) in enumerate(args)]) | |
74 | or 'void') | |
75 | ||
76 | source = list(cdefs) | |
77 | ||
78 | cdefs.append("%s;" % signature) | |
79 | cdefs.append("extern %s testfargs_result;" % result) | |
80 | for i, arg in enumerate(args): | |
81 | cdefs.append("extern %s testfargs_arg%d;" % (arg, i)) | |
82 | source.append("%s testfargs_result;" % result) | |
83 | for i, arg in enumerate(args): | |
84 | source.append("%s testfargs_arg%d;" % (arg, i)) | |
85 | source.append(signature) | |
86 | source.append("{") | |
87 | for i, arg in enumerate(args): | |
88 | source.append(" testfargs_arg%d = a%d;" % (i, i)) | |
89 | source.append(" return testfargs_result;") | |
90 | source.append("}") | |
91 | ||
92 | typedef_line = "typedef %s;" % (signature.replace('testfargs', | |
93 | '(*mycallback_t)'),) | |
94 | assert signature.endswith(')') | |
95 | sig_callback = "%s testfcallback(mycallback_t callback)" % result | |
96 | cdefs.append(typedef_line) | |
97 | cdefs.append("%s;" % sig_callback) | |
98 | source.append(typedef_line) | |
99 | source.append(sig_callback) | |
100 | source.append("{") | |
101 | source.append(" return callback(%s);" % | |
102 | ', '.join(["testfargs_arg%d" % i for i in range(len(args))])) | |
103 | source.append("}") | |
104 | ||
105 | ffi = FFI() | |
106 | ffi.cdef("\n".join(cdefs)) | |
107 | lib = verify(ffi, 'test_function_args_%d' % TEST_RUN_COUNTER, | |
108 | "\n".join(source), no_cpp=True) | |
109 | ||
110 | # when getting segfaults, enable this: | |
111 | if False: | |
112 | from testing.udir import udir | |
113 | import subprocess | |
114 | f = open(str(udir.join('run1.py')), 'w') | |
115 | f.write('import sys; sys.path = %r\n' % (sys.path,)) | |
116 | f.write('from _CFFI_test_function_args_%d import ffi, lib\n' % | |
117 | TEST_RUN_COUNTER) | |
118 | for i in range(len(args)): | |
119 | f.write('a%d = ffi.new("%s *")\n' % (i, args[i])) | |
120 | aliststr = ', '.join(['a%d[0]' % i for i in range(len(args))]) | |
121 | f.write('lib.testfargs(%s)\n' % aliststr) | |
122 | f.write('ffi.addressof(lib, "testfargs")(%s)\n' % aliststr) | |
123 | f.close() | |
124 | print("checking for segfault for direct call...") | |
125 | rc = subprocess.call([sys.executable, 'run1.py'], cwd=str(udir)) | |
126 | assert rc == 0, rc | |
127 | ||
128 | def make_arg(tp): | |
129 | if tp in structs: | |
130 | return [make_arg(tp1) for tp1 in structs[tp]] | |
131 | else: | |
132 | return draw_primitive(ffi, tp) | |
133 | ||
134 | passed_args = [make_arg(arg) for arg in args] | |
135 | returned_value = make_arg(result) | |
136 | ||
137 | def write(p, v): | |
138 | if type(v) is list: | |
139 | for i, v1 in enumerate(v): | |
140 | write(ffi.addressof(p, 'f%d' % i), v1) | |
141 | else: | |
142 | p[0] = v | |
143 | ||
144 | write(ffi.addressof(lib, 'testfargs_result'), returned_value) | |
145 | ||
146 | ## CALL forcing libffi | |
147 | print("CALL forcing libffi") | |
148 | received_return = ffi.addressof(lib, 'testfargs')(*passed_args) | |
149 | ## | |
150 | ||
151 | _tp_long_double = ffi.typeof("long double") | |
152 | def check(p, v): | |
153 | if type(v) is list: | |
154 | for i, v1 in enumerate(v): | |
155 | check(ffi.addressof(p, 'f%d' % i), v1) | |
156 | else: | |
157 | if ffi.typeof(p).item is _tp_long_double: | |
158 | assert ffi.cast("double", p[0]) == v | |
159 | else: | |
160 | assert p[0] == v | |
161 | ||
162 | for i, arg in enumerate(passed_args): | |
163 | check(ffi.addressof(lib, 'testfargs_arg%d' % i), arg) | |
164 | ret = ffi.new(result + "*", received_return) | |
165 | check(ret, returned_value) | |
166 | ||
167 | ## CALLBACK | |
168 | def expand(value): | |
169 | if isinstance(value, ffi.CData): | |
170 | t = ffi.typeof(value) | |
171 | if t is _tp_long_double: | |
172 | return float(ffi.cast("double", value)) | |
173 | return [expand(getattr(value, 'f%d' % i)) | |
174 | for i in range(len(t.fields))] | |
175 | else: | |
176 | return value | |
177 | ||
178 | # when getting segfaults, enable this: | |
179 | if False: | |
180 | from testing.udir import udir | |
181 | import subprocess | |
182 | f = open(str(udir.join('run1.py')), 'w') | |
183 | f.write('import sys; sys.path = %r\n' % (sys.path,)) | |
184 | f.write('from _CFFI_test_function_args_%d import ffi, lib\n' % | |
185 | TEST_RUN_COUNTER) | |
186 | f.write('def callback(*args): return ffi.new("%s *")[0]\n' % result) | |
187 | f.write('fptr = ffi.callback("%s(%s)", callback)\n' % (result, | |
188 | ','.join(args))) | |
189 | f.write('print(lib.testfcallback(fptr))\n') | |
190 | f.close() | |
191 | print("checking for segfault for callback...") | |
192 | rc = subprocess.call([sys.executable, 'run1.py'], cwd=str(udir)) | |
193 | assert rc == 0, rc | |
194 | ||
195 | seen_args = [] | |
196 | def callback(*args): | |
197 | seen_args.append([expand(arg) for arg in args]) | |
198 | return returned_value | |
199 | ||
200 | fptr = ffi.callback("%s(%s)" % (result, ','.join(args)), callback) | |
201 | print("CALL with callback") | |
202 | received_return = lib.testfcallback(fptr) | |
203 | ||
204 | assert len(seen_args) == 1 | |
205 | assert passed_args == seen_args[0] | |
206 | ret = ffi.new(result + "*", received_return) | |
207 | check(ret, returned_value) |
73 | 73 | int strlen(const char *); |
74 | 74 | struct with_union { union { int a; char b; }; }; |
75 | 75 | union with_struct { struct { int a; char b; }; }; |
76 | struct with_struct_with_union { struct { union { int x; }; } cp; }; | |
76 | 77 | struct NVGcolor { union { float rgba[4]; struct { float r,g,b,a; }; }; }; |
77 | 78 | typedef struct selfref { struct selfref *next; } *selfref_ptr_t; |
78 | 79 | """) |
246 | 247 | assert ffi.offsetof("union with_struct", "a") == 0 |
247 | 248 | assert ffi.offsetof("union with_struct", "b") == INT |
248 | 249 | assert ffi.sizeof("union with_struct") >= INT + 1 |
250 | # | |
251 | assert ffi.sizeof("struct with_struct_with_union") == INT | |
252 | p = ffi.new("struct with_struct_with_union *") | |
253 | assert p.cp.x == 0 | |
249 | 254 | # |
250 | 255 | FLOAT = ffi.sizeof("float") |
251 | 256 | assert ffi.sizeof("struct NVGcolor") == FLOAT * 4 |
37 | 37 | from testing.support import extra_compile_args |
38 | 38 | kwds['extra_compile_args'] = (kwds.get('extra_compile_args', []) + |
39 | 39 | extra_compile_args) |
40 | if sys.platform == 'darwin': | |
41 | kwds['extra_link_args'] = (kwds.get('extra_link_args', []) + | |
42 | ['-stdlib=libc++']) | |
40 | 43 | return _verify(ffi, module_name, source, *args, **kwds) |
41 | 44 | |
42 | 45 | def test_set_source_no_slashes(): |
885 | 888 | e7 = py.test.raises(TypeError, lib.foo2, 45, 46, 47) |
886 | 889 | def st1(s): |
887 | 890 | s = str(s) |
888 | if s.startswith("_CFFI_test_unpack_args.CompiledLib."): | |
889 | s = s[len("_CFFI_test_unpack_args.CompiledLib."):] | |
891 | if s.startswith("_CFFI_test_unpack_args.Lib."): | |
892 | s = s[len("_CFFI_test_unpack_args.Lib."):] | |
890 | 893 | return s |
891 | 894 | assert st1(e1.value) == "foo0() takes no arguments (1 given)" |
892 | 895 | assert st1(e2.value) == "foo0() takes no arguments (2 given)" |
1665 | 1668 | with StdErrCapture() as f: |
1666 | 1669 | res = lib.bar(321) |
1667 | 1670 | assert res is None |
1668 | assert f.getvalue() == ( | |
1669 | "From cffi callback %r:\n" % (bar,) + | |
1670 | "Trying to convert the result back to C:\n" | |
1671 | msg = f.getvalue() | |
1672 | assert "rom cffi callback %r" % (bar,) in msg | |
1673 | assert "rying to convert the result back to C:\n" in msg | |
1674 | assert msg.endswith( | |
1671 | 1675 | "TypeError: callback with the return type 'void' must return None\n") |
1672 | 1676 | |
1673 | 1677 | def test_extern_python_redefine(): |
2117 | 2121 | py.test.raises(ffi.error, ffi.sizeof, "vmat_t") |
2118 | 2122 | p = ffi.new("vmat_t", 4) |
2119 | 2123 | assert ffi.sizeof(p[3]) == 8 * ffi.sizeof("int") |
2124 | ||
2125 | def test_typedef_array_dotdotdot_usage(): | |
2126 | ffi = FFI() | |
2127 | ffi.cdef(""" | |
2128 | typedef int foo_t[...]; | |
2129 | typedef int mat_t[...][...]; | |
2130 | struct s { foo_t a; foo_t *b; foo_t **c; }; | |
2131 | int myfunc(foo_t a, foo_t *b, foo_t **c); | |
2132 | struct sm { mat_t a; mat_t *b; mat_t **c; }; | |
2133 | int myfuncm(mat_t a, mat_t *b, mat_t **c); | |
2134 | """) | |
2135 | lib = verify(ffi, "test_typedef_array_dotdotdot_usage", """ | |
2136 | typedef int foo_t[50]; | |
2137 | typedef int mat_t[6][7]; | |
2138 | struct s { foo_t a; foo_t *b; foo_t **c; }; | |
2139 | static int myfunc(foo_t a, foo_t *b, foo_t **c) { return (**c)[49]; } | |
2140 | struct sm { mat_t a; mat_t *b; mat_t **c; }; | |
2141 | static int myfuncm(mat_t a, mat_t *b, mat_t **c) { return (**c)[5][6]; } | |
2142 | """) | |
2143 | assert ffi.sizeof("foo_t") == 50 * ffi.sizeof("int") | |
2144 | p = ffi.new("struct s *") | |
2145 | assert ffi.sizeof(p[0]) == 50 * ffi.sizeof("int") + 2 * ffi.sizeof("void *") | |
2146 | p.a[49] = 321 | |
2147 | p.b = ffi.addressof(p, 'a') | |
2148 | p.c = ffi.addressof(p, 'b') | |
2149 | assert lib.myfunc(ffi.NULL, ffi.NULL, p.c) == 321 | |
2150 | # | |
2151 | assert ffi.sizeof("mat_t") == 42 * ffi.sizeof("int") | |
2152 | p = ffi.new("struct sm *") | |
2153 | assert ffi.sizeof(p[0]) == 42 * ffi.sizeof("int") + 2 * ffi.sizeof("void *") | |
2154 | p.a[5][6] = -321 | |
2155 | p.b = ffi.addressof(p, 'a') | |
2156 | p.c = ffi.addressof(p, 'b') | |
2157 | assert lib.myfuncm(ffi.NULL, ffi.NULL, p.c) == -321 | |
2120 | 2158 | |
2121 | 2159 | def test_call_with_custom_field_pos(): |
2122 | 2160 | ffi = FFI() |
205 | 205 | self.compile('add1-test', [initerror_cffi]) |
206 | 206 | output = self.execute('add1-test') |
207 | 207 | assert output == "got: 0 0\n" # plus lots of info to stderr |
208 | ||
209 | def test_embedding_with_unicode(self): | |
210 | withunicode_cffi = self.prepare_module('withunicode') | |
211 | self.compile('add1-test', [withunicode_cffi]) | |
212 | output = self.execute('add1-test') | |
213 | assert output == "255\n4660\n65244\ngot: 0 0\n" |
0 | import sys, cffi | |
1 | if sys.version_info < (3,): | |
2 | u_prefix = "u" | |
3 | else: | |
4 | u_prefix = "" | |
5 | unichr = chr | |
6 | ||
7 | ||
8 | ffi = cffi.FFI() | |
9 | ||
10 | ffi.embedding_api(u""" | |
11 | int add1(int, int); | |
12 | """) | |
13 | ||
14 | ffi.embedding_init_code((""" | |
15 | import sys, time | |
16 | for c in %s'""" + unichr(0x00ff) + unichr(0x1234) + unichr(0xfedc) + """': | |
17 | sys.stdout.write(str(ord(c)) + '\\n') | |
18 | sys.stdout.flush() | |
19 | """) % u_prefix) | |
20 | ||
21 | ffi.set_source("_withunicode_cffi", """ | |
22 | """) | |
23 | ||
24 | fn = ffi.compile(verbose=True) | |
25 | print('FILENAME: %s' % (fn,)) |
32 | 32 | from io import StringIO |
33 | 33 | self.old_stderr = sys.stderr |
34 | 34 | sys.stderr = f = StringIO() |
35 | if hasattr(sys, '__unraisablehook__'): # work around pytest | |
36 | self.old_unraisablebook = sys.unraisablehook # on recent CPythons | |
37 | sys.unraisablehook = sys.__unraisablehook__ | |
35 | 38 | return f |
36 | 39 | def __exit__(self, *args): |
37 | 40 | sys.stderr = self.old_stderr |
41 | if hasattr(self, 'old_unraisablebook'): | |
42 | sys.unraisablehook = self.old_unraisablebook | |
38 | 43 | |
39 | 44 | |
40 | 45 | class FdWriteCapture(object): |
0 | 0 | import py |
1 | import sys | |
1 | import sys, os, atexit | |
2 | 2 | |
3 | udir = py.path.local.make_numbered_dir(prefix = 'ffi-') | |
3 | ||
4 | # This is copied from PyPy's vendored py lib. The latest py lib release | |
5 | # (1.8.1) contains a bug and crashes if it sees another temporary directory | |
6 | # in which we don't have write permission (e.g. because it's owned by someone | |
7 | # else). | |
8 | def make_numbered_dir(prefix='session-', rootdir=None, keep=3, | |
9 | lock_timeout = 172800, # two days | |
10 | min_timeout = 300): # five minutes | |
11 | """ return unique directory with a number greater than the current | |
12 | maximum one. The number is assumed to start directly after prefix. | |
13 | if keep is true directories with a number less than (maxnum-keep) | |
14 | will be removed. | |
15 | """ | |
16 | if rootdir is None: | |
17 | rootdir = py.path.local.get_temproot() | |
18 | ||
19 | def parse_num(path): | |
20 | """ parse the number out of a path (if it matches the prefix) """ | |
21 | bn = path.basename | |
22 | if bn.startswith(prefix): | |
23 | try: | |
24 | return int(bn[len(prefix):]) | |
25 | except ValueError: | |
26 | pass | |
27 | ||
28 | # compute the maximum number currently in use with the | |
29 | # prefix | |
30 | lastmax = None | |
31 | while True: | |
32 | maxnum = -1 | |
33 | for path in rootdir.listdir(): | |
34 | num = parse_num(path) | |
35 | if num is not None: | |
36 | maxnum = max(maxnum, num) | |
37 | ||
38 | # make the new directory | |
39 | try: | |
40 | udir = rootdir.mkdir(prefix + str(maxnum+1)) | |
41 | except py.error.EEXIST: | |
42 | # race condition: another thread/process created the dir | |
43 | # in the meantime. Try counting again | |
44 | if lastmax == maxnum: | |
45 | raise | |
46 | lastmax = maxnum | |
47 | continue | |
48 | break | |
49 | ||
50 | # put a .lock file in the new directory that will be removed at | |
51 | # process exit | |
52 | if lock_timeout: | |
53 | lockfile = udir.join('.lock') | |
54 | mypid = os.getpid() | |
55 | if hasattr(lockfile, 'mksymlinkto'): | |
56 | lockfile.mksymlinkto(str(mypid)) | |
57 | else: | |
58 | lockfile.write(str(mypid)) | |
59 | def try_remove_lockfile(): | |
60 | # in a fork() situation, only the last process should | |
61 | # remove the .lock, otherwise the other processes run the | |
62 | # risk of seeing their temporary dir disappear. For now | |
63 | # we remove the .lock in the parent only (i.e. we assume | |
64 | # that the children finish before the parent). | |
65 | if os.getpid() != mypid: | |
66 | return | |
67 | try: | |
68 | lockfile.remove() | |
69 | except py.error.Error: | |
70 | pass | |
71 | atexit.register(try_remove_lockfile) | |
72 | ||
73 | # prune old directories | |
74 | if keep: | |
75 | for path in rootdir.listdir(): | |
76 | num = parse_num(path) | |
77 | if num is not None and num <= (maxnum - keep): | |
78 | if min_timeout: | |
79 | # NB: doing this is needed to prevent (or reduce | |
80 | # a lot the chance of) the following situation: | |
81 | # 'keep+1' processes call make_numbered_dir() at | |
82 | # the same time, they create dirs, but then the | |
83 | # last process notices the first dir doesn't have | |
84 | # (yet) a .lock in it and kills it. | |
85 | try: | |
86 | t1 = path.lstat().mtime | |
87 | t2 = lockfile.lstat().mtime | |
88 | if abs(t2-t1) < min_timeout: | |
89 | continue # skip directories too recent | |
90 | except py.error.Error: | |
91 | continue # failure to get a time, better skip | |
92 | lf = path.join('.lock') | |
93 | try: | |
94 | t1 = lf.lstat().mtime | |
95 | t2 = lockfile.lstat().mtime | |
96 | if not lock_timeout or abs(t2-t1) < lock_timeout: | |
97 | continue # skip directories still locked | |
98 | except py.error.Error: | |
99 | pass # assume that it means that there is no 'lf' | |
100 | try: | |
101 | path.remove(rec=1) | |
102 | except KeyboardInterrupt: | |
103 | raise | |
104 | except: # this might be py.error.Error, WindowsError ... | |
105 | pass | |
106 | ||
107 | # make link... | |
108 | try: | |
109 | username = os.environ['USER'] #linux, et al | |
110 | except KeyError: | |
111 | try: | |
112 | username = os.environ['USERNAME'] #windows | |
113 | except KeyError: | |
114 | username = 'current' | |
115 | ||
116 | src = str(udir) | |
117 | dest = src[:src.rfind('-')] + '-' + username | |
118 | try: | |
119 | os.unlink(dest) | |
120 | except OSError: | |
121 | pass | |
122 | try: | |
123 | os.symlink(src, dest) | |
124 | except (OSError, AttributeError, NotImplementedError): | |
125 | pass | |
126 | ||
127 | return udir | |
128 | ||
129 | ||
130 | udir = make_numbered_dir(prefix = 'ffi-') | |
4 | 131 | |
5 | 132 | |
6 | 133 | # Windows-only workaround for some configurations: see |