11
11
12
12
#include "npy_config.h"
13
13
14
+ #include "npy_import.h"
14
15
#include "npy_pycompat.h"
15
16
#include "multiarraymodule.h"
16
17
@@ -1312,16 +1313,6 @@ _dtype_from_buffer_3118(PyObject *memoryview)
1312
1313
if (descr == NULL ) {
1313
1314
return NULL ;
1314
1315
}
1315
-
1316
- /* Sanity check */
1317
- if (descr -> elsize != view -> itemsize ) {
1318
- PyErr_SetString (
1319
- PyExc_RuntimeError ,
1320
- "Item size computed from the PEP 3118 buffer format "
1321
- "string does not match the actual item size." );
1322
- Py_DECREF (descr );
1323
- return NULL ;
1324
- }
1325
1316
}
1326
1317
else {
1327
1318
/* If no format is specified, just assume a byte array
@@ -1335,6 +1326,28 @@ _dtype_from_buffer_3118(PyObject *memoryview)
1335
1326
}
1336
1327
1337
1328
1329
+ /*
1330
+ * Call the python _is_from_ctypes
1331
+ */
1332
+ NPY_NO_EXPORT int
1333
+ _is_from_ctypes (PyObject * obj ) {
1334
+ PyObject * ret_obj ;
1335
+ static PyObject * py_func = NULL ;
1336
+
1337
+ npy_cache_import ("numpy.core._internal" , "_is_from_ctypes" , & py_func );
1338
+
1339
+ if (py_func == NULL ) {
1340
+ return -1 ;
1341
+ }
1342
+ ret_obj = PyObject_CallFunctionObjArgs (py_func , obj , NULL );
1343
+ if (ret_obj == NULL ) {
1344
+ return -1 ;
1345
+ }
1346
+
1347
+ return PyObject_IsTrue (ret_obj );
1348
+ }
1349
+
1350
+
1338
1351
NPY_NO_EXPORT PyObject *
1339
1352
_array_from_buffer_3118 (PyObject * memoryview )
1340
1353
{
@@ -1354,6 +1367,68 @@ _array_from_buffer_3118(PyObject *memoryview)
1354
1367
return NULL ;
1355
1368
}
1356
1369
1370
+ /* Sanity check */
1371
+ if (descr -> elsize != view -> itemsize ) {
1372
+ /* Ctypes has bugs in its PEP3118 implementation, which we need to
1373
+ * work around.
1374
+ *
1375
+ * bpo-10746
1376
+ * bpo-32780
1377
+ * bpo-32782
1378
+ *
1379
+ * Note that even if the above are fixed in master, we have to drop the
1380
+ * early patch versions of python to actually make use of the fixes.
1381
+ */
1382
+
1383
+ int is_ctypes = _is_from_ctypes (view -> obj );
1384
+ if (is_ctypes < 0 ) {
1385
+ /* This error is not useful */
1386
+ PyErr_WriteUnraisable (view -> obj );
1387
+ is_ctypes = 0 ;
1388
+ }
1389
+
1390
+ if (!is_ctypes ) {
1391
+ /* This object has no excuse for a broken PEP3118 buffer */
1392
+ PyErr_SetString (
1393
+ PyExc_RuntimeError ,
1394
+ "Item size computed from the PEP 3118 buffer format "
1395
+ "string does not match the actual item size." );
1396
+ Py_DECREF (descr );
1397
+ return NULL ;
1398
+ }
1399
+
1400
+ if (PyErr_Warn (
1401
+ PyExc_RuntimeWarning ,
1402
+ "A builtin ctypes object gave a PEP3118 format "
1403
+ "string that does not match its itemsize, so a "
1404
+ "best-guess will be made of the data type. "
1405
+ "Newer versions of python may behave correctly." ) < 0 ) {
1406
+ Py_DECREF (descr );
1407
+ return NULL ;
1408
+ }
1409
+
1410
+ /* Thankfully, np.dtype(ctypes_type) works in most cases.
1411
+ * For an array input, this produces a dtype containing all the
1412
+ * dimensions, so the array is now 0d.
1413
+ */
1414
+ nd = 0 ;
1415
+ descr = (PyArray_Descr * )PyObject_CallFunctionObjArgs (
1416
+ (PyObject * )& PyArrayDescr_Type , Py_TYPE (view -> obj ), NULL );
1417
+ if (descr == NULL ) {
1418
+ return NULL ;
1419
+ }
1420
+ if (descr -> elsize != view -> len ) {
1421
+ PyErr_SetString (
1422
+ PyExc_RuntimeError ,
1423
+ "For the given ctypes object, neither the item size "
1424
+ "computed from the PEP 3118 buffer format nor from "
1425
+ "converting the type to a np.dtype matched the actual "
1426
+ "size. This is a bug both in python and numpy" );
1427
+ Py_DECREF (descr );
1428
+ return NULL ;
1429
+ }
1430
+ }
1431
+
1357
1432
if (view -> shape != NULL ) {
1358
1433
int k ;
1359
1434
if (nd > NPY_MAXDIMS || nd < 0 ) {
@@ -1399,6 +1474,7 @@ _array_from_buffer_3118(PyObject *memoryview)
1399
1474
flags , NULL , memoryview );
1400
1475
return r ;
1401
1476
1477
+
1402
1478
fail :
1403
1479
Py_XDECREF (r );
1404
1480
Py_XDECREF (descr );
0 commit comments