Cython/15de63e460.patch
2023-03-07 10:09:28 +01:00

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",