116 lines
5.1 KiB
Diff
116 lines
5.1 KiB
Diff
From 15de63e460e8a634aeb6bede0ba40ffa759f8c08 Mon Sep 17 00:00:00 2001
|
|
From: da-woods <dw-git@d-woods.co.uk>
|
|
Date: Sun, 17 Jul 2022 10:51:11 +0100
|
|
Subject: [PATCH] Account for possible extension type struct padding when
|
|
calculating the itemsize for the "size changed" check (GH-4894)
|
|
|
|
---
|
|
Cython/Compiler/ModuleNode.py | 6 +++---
|
|
Cython/Utility/ImportExport.c | 40 ++++++++++++++++++++++++++++++++---
|
|
2 files changed, 40 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py
|
|
index 56845330df..e81b63d0a6 100644
|
|
--- a/Cython/Compiler/ModuleNode.py
|
|
+++ b/Cython/Compiler/ModuleNode.py
|
|
@@ -3078,12 +3078,12 @@ def generate_type_import_call(self, type, code, import_generator, error_code=Non
|
|
if not condition:
|
|
code.putln("") # start in new line
|
|
code.putln("#if defined(PYPY_VERSION_NUM) && PYPY_VERSION_NUM < 0x050B0000")
|
|
- code.putln('sizeof(%s),' % objstruct)
|
|
+ code.putln('sizeof(%s), __PYX_GET_STRUCT_ALIGNMENT(%s),' % (objstruct, objstruct))
|
|
code.putln("#else")
|
|
- code.putln('sizeof(%s),' % sizeof_objstruct)
|
|
+ code.putln('sizeof(%s), __PYX_GET_STRUCT_ALIGNMENT(%s),' % (sizeof_objstruct, sizeof_objstruct))
|
|
code.putln("#endif")
|
|
else:
|
|
- code.put('sizeof(%s), ' % objstruct)
|
|
+ code.putln('sizeof(%s), __PYX_GET_STRUCT_ALIGNMENT(%s),' % (objstruct, objstruct))
|
|
|
|
# check_size
|
|
if type.check_size and type.check_size in ('error', 'warn', 'ignore'):
|
|
diff --git a/Cython/Utility/ImportExport.c b/Cython/Utility/ImportExport.c
|
|
index 1689c11381..e1458fc8ff 100644
|
|
--- a/Cython/Utility/ImportExport.c
|
|
+++ b/Cython/Utility/ImportExport.c
|
|
@@ -301,13 +301,24 @@ static int __Pyx_SetPackagePathFromImportLib(PyObject *module_name) {
|
|
#ifndef __PYX_HAVE_RT_ImportType_proto
|
|
#define __PYX_HAVE_RT_ImportType_proto
|
|
|
|
+#if __STDC_VERSION__ >= 201112L
|
|
+#include <stdalign.h>
|
|
+#endif
|
|
+
|
|
+#if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L
|
|
+#define __PYX_GET_STRUCT_ALIGNMENT(s) alignof(s)
|
|
+#else
|
|
+// best guess at what the alignment could be since we can't measure it
|
|
+#define __PYX_GET_STRUCT_ALIGNMENT(s) sizeof(void*)
|
|
+#endif
|
|
+
|
|
enum __Pyx_ImportType_CheckSize {
|
|
__Pyx_ImportType_CheckSize_Error = 0,
|
|
__Pyx_ImportType_CheckSize_Warn = 1,
|
|
__Pyx_ImportType_CheckSize_Ignore = 2
|
|
};
|
|
|
|
-static PyTypeObject *__Pyx_ImportType(PyObject* module, const char *module_name, const char *class_name, size_t size, enum __Pyx_ImportType_CheckSize check_size); /*proto*/
|
|
+static PyTypeObject *__Pyx_ImportType(PyObject* module, const char *module_name, const char *class_name, size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize check_size); /*proto*/
|
|
|
|
#endif
|
|
|
|
@@ -316,13 +327,15 @@ static PyTypeObject *__Pyx_ImportType(PyObject* module, const char *module_name,
|
|
#ifndef __PYX_HAVE_RT_ImportType
|
|
#define __PYX_HAVE_RT_ImportType
|
|
static PyTypeObject *__Pyx_ImportType(PyObject *module, const char *module_name, const char *class_name,
|
|
- size_t size, enum __Pyx_ImportType_CheckSize check_size)
|
|
+ size_t size, size_t alignment, enum __Pyx_ImportType_CheckSize check_size)
|
|
{
|
|
PyObject *result = 0;
|
|
char warning[200];
|
|
Py_ssize_t basicsize;
|
|
+ Py_ssize_t itemsize;
|
|
#ifdef Py_LIMITED_API
|
|
PyObject *py_basicsize;
|
|
+ PyObject *py_itemsize;
|
|
#endif
|
|
|
|
result = PyObject_GetAttrString(module, class_name);
|
|
@@ -336,6 +349,7 @@ static PyTypeObject *__Pyx_ImportType(PyObject *module, const char *module_name,
|
|
}
|
|
#ifndef Py_LIMITED_API
|
|
basicsize = ((PyTypeObject *)result)->tp_basicsize;
|
|
+ itemsize = ((PyTypeObject *)result)->tp_itemsize;
|
|
#else
|
|
py_basicsize = PyObject_GetAttrString(result, "__basicsize__");
|
|
if (!py_basicsize)
|
|
@@ -345,8 +359,28 @@ static PyTypeObject *__Pyx_ImportType(PyObject *module, const char *module_name,
|
|
py_basicsize = 0;
|
|
if (basicsize == (Py_ssize_t)-1 && PyErr_Occurred())
|
|
goto bad;
|
|
+ py_itemsize = PyObject_GetAttrString(result, "__itemsize__");
|
|
+ if (!py_itemsize)
|
|
+ goto bad;
|
|
+ itemsize = PyLong_AsSsize_t(py_itemsize);
|
|
+ Py_DECREF(py_itemsize);
|
|
+ py_itemsize = 0;
|
|
+ if (itemsize == (Py_ssize_t)-1 && PyErr_Occurred())
|
|
+ goto bad;
|
|
#endif
|
|
- if ((size_t)basicsize < size) {
|
|
+ if (itemsize) {
|
|
+ // If itemsize is smaller than the alignment the struct can end up with some extra
|
|
+ // padding at the end. In this case we need to work out the maximum size that
|
|
+ // the padding could be when calculating the range of valid struct sizes.
|
|
+ if (size % alignment) {
|
|
+ // if this is true we've probably calculated the alignment wrongly
|
|
+ // (most likely because alignof isn't available)
|
|
+ alignment = size % alignment;
|
|
+ }
|
|
+ if (itemsize < (Py_ssize_t)alignment)
|
|
+ itemsize = (Py_ssize_t)alignment;
|
|
+ }
|
|
+ if ((size_t)(basicsize + itemsize) < size) {
|
|
PyErr_Format(PyExc_ValueError,
|
|
"%.200s.%.200s size changed, may indicate binary incompatibility. "
|
|
"Expected %zd from C header, got %zd from PyObject",
|