mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-12 18:26:17 +03:00
Merge pull request #8496 from lysnikolaou/fix-font-face-threading-crash
Fix SEGFAULT from calling FT_New_Face/FT_Done_Face in multiple threads
This commit is contained in:
commit
9a4b3e05d6
|
@ -82,6 +82,9 @@ struct {
|
|||
/* font objects */
|
||||
|
||||
static FT_Library library;
|
||||
#ifdef Py_GIL_DISABLED
|
||||
static PyMutex ft_library_mutex;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD FT_Face face;
|
||||
|
@ -187,7 +190,9 @@ getfont(PyObject *self_, PyObject *args, PyObject *kw) {
|
|||
|
||||
if (filename && font_bytes_size <= 0) {
|
||||
self->font_bytes = NULL;
|
||||
MUTEX_LOCK(&ft_library_mutex);
|
||||
error = FT_New_Face(library, filename, index, &self->face);
|
||||
MUTEX_UNLOCK(&ft_library_mutex);
|
||||
} else {
|
||||
/* need to have allocated storage for font_bytes for the life of the object.*/
|
||||
/* Don't free this before FT_Done_Face */
|
||||
|
@ -197,6 +202,7 @@ getfont(PyObject *self_, PyObject *args, PyObject *kw) {
|
|||
}
|
||||
if (!error) {
|
||||
memcpy(self->font_bytes, font_bytes, (size_t)font_bytes_size);
|
||||
MUTEX_LOCK(&ft_library_mutex);
|
||||
error = FT_New_Memory_Face(
|
||||
library,
|
||||
(FT_Byte *)self->font_bytes,
|
||||
|
@ -204,6 +210,7 @@ getfont(PyObject *self_, PyObject *args, PyObject *kw) {
|
|||
index,
|
||||
&self->face
|
||||
);
|
||||
MUTEX_UNLOCK(&ft_library_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1433,7 +1440,9 @@ font_setvaraxes(FontObject *self, PyObject *args) {
|
|||
static void
|
||||
font_dealloc(FontObject *self) {
|
||||
if (self->face) {
|
||||
MUTEX_LOCK(&ft_library_mutex);
|
||||
FT_Done_Face(self->face);
|
||||
MUTEX_UNLOCK(&ft_library_mutex);
|
||||
}
|
||||
if (self->font_bytes) {
|
||||
PyMem_Free(self->font_bytes);
|
||||
|
|
341
src/thirdparty/pythoncapi_compat.h
vendored
341
src/thirdparty/pythoncapi_compat.h
vendored
|
@ -7,7 +7,10 @@
|
|||
// https://github.com/python/pythoncapi_compat
|
||||
//
|
||||
// Latest version:
|
||||
// https://raw.githubusercontent.com/python/pythoncapi_compat/master/pythoncapi_compat.h
|
||||
// https://raw.githubusercontent.com/python/pythoncapi-compat/main/pythoncapi_compat.h
|
||||
//
|
||||
// This file was vendored from the following commit:
|
||||
// https://github.com/python/pythoncapi-compat/commit/0041177c4f348c8952b4c8980b2c90856e61c7c7
|
||||
//
|
||||
// SPDX-License-Identifier: 0BSD
|
||||
|
||||
|
@ -45,6 +48,13 @@ extern "C" {
|
|||
# define _PyObject_CAST(op) _Py_CAST(PyObject*, op)
|
||||
#endif
|
||||
|
||||
#ifndef Py_BUILD_ASSERT
|
||||
# define Py_BUILD_ASSERT(cond) \
|
||||
do { \
|
||||
(void)sizeof(char [1 - 2 * !(cond)]); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-42262 added Py_NewRef() to Python 3.10.0a3
|
||||
#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_NewRef)
|
||||
|
@ -1338,6 +1348,166 @@ PyDict_SetDefaultRef(PyObject *d, PyObject *key, PyObject *default_value,
|
|||
}
|
||||
#endif
|
||||
|
||||
#if PY_VERSION_HEX < 0x030D00B3
|
||||
# define Py_BEGIN_CRITICAL_SECTION(op) {
|
||||
# define Py_END_CRITICAL_SECTION() }
|
||||
# define Py_BEGIN_CRITICAL_SECTION2(a, b) {
|
||||
# define Py_END_CRITICAL_SECTION2() }
|
||||
#endif
|
||||
|
||||
#if PY_VERSION_HEX < 0x030E0000 && PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION)
|
||||
typedef struct PyUnicodeWriter PyUnicodeWriter;
|
||||
|
||||
static inline void PyUnicodeWriter_Discard(PyUnicodeWriter *writer)
|
||||
{
|
||||
_PyUnicodeWriter_Dealloc((_PyUnicodeWriter*)writer);
|
||||
PyMem_Free(writer);
|
||||
}
|
||||
|
||||
static inline PyUnicodeWriter* PyUnicodeWriter_Create(Py_ssize_t length)
|
||||
{
|
||||
if (length < 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"length must be positive");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const size_t size = sizeof(_PyUnicodeWriter);
|
||||
PyUnicodeWriter *pub_writer = (PyUnicodeWriter *)PyMem_Malloc(size);
|
||||
if (pub_writer == _Py_NULL) {
|
||||
PyErr_NoMemory();
|
||||
return _Py_NULL;
|
||||
}
|
||||
_PyUnicodeWriter *writer = (_PyUnicodeWriter *)pub_writer;
|
||||
|
||||
_PyUnicodeWriter_Init(writer);
|
||||
if (_PyUnicodeWriter_Prepare(writer, length, 127) < 0) {
|
||||
PyUnicodeWriter_Discard(pub_writer);
|
||||
return NULL;
|
||||
}
|
||||
writer->overallocate = 1;
|
||||
return pub_writer;
|
||||
}
|
||||
|
||||
static inline PyObject* PyUnicodeWriter_Finish(PyUnicodeWriter *writer)
|
||||
{
|
||||
PyObject *str = _PyUnicodeWriter_Finish((_PyUnicodeWriter*)writer);
|
||||
assert(((_PyUnicodeWriter*)writer)->buffer == NULL);
|
||||
PyMem_Free(writer);
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline int
|
||||
PyUnicodeWriter_WriteChar(PyUnicodeWriter *writer, Py_UCS4 ch)
|
||||
{
|
||||
if (ch > 0x10ffff) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"character must be in range(0x110000)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _PyUnicodeWriter_WriteChar((_PyUnicodeWriter*)writer, ch);
|
||||
}
|
||||
|
||||
static inline int
|
||||
PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj)
|
||||
{
|
||||
PyObject *str = PyObject_Str(obj);
|
||||
if (str == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
|
||||
Py_DECREF(str);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int
|
||||
PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj)
|
||||
{
|
||||
PyObject *str = PyObject_Repr(obj);
|
||||
if (str == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
|
||||
Py_DECREF(str);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int
|
||||
PyUnicodeWriter_WriteUTF8(PyUnicodeWriter *writer,
|
||||
const char *str, Py_ssize_t size)
|
||||
{
|
||||
if (size < 0) {
|
||||
size = (Py_ssize_t)strlen(str);
|
||||
}
|
||||
|
||||
PyObject *str_obj = PyUnicode_FromStringAndSize(str, size);
|
||||
if (str_obj == _Py_NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str_obj);
|
||||
Py_DECREF(str_obj);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int
|
||||
PyUnicodeWriter_WriteWideChar(PyUnicodeWriter *writer,
|
||||
const wchar_t *str, Py_ssize_t size)
|
||||
{
|
||||
if (size < 0) {
|
||||
size = (Py_ssize_t)wcslen(str);
|
||||
}
|
||||
|
||||
PyObject *str_obj = PyUnicode_FromWideChar(str, size);
|
||||
if (str_obj == _Py_NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str_obj);
|
||||
Py_DECREF(str_obj);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int
|
||||
PyUnicodeWriter_WriteSubstring(PyUnicodeWriter *writer, PyObject *str,
|
||||
Py_ssize_t start, Py_ssize_t end)
|
||||
{
|
||||
if (!PyUnicode_Check(str)) {
|
||||
PyErr_Format(PyExc_TypeError, "expect str, not %T", str);
|
||||
return -1;
|
||||
}
|
||||
if (start < 0 || start > end) {
|
||||
PyErr_Format(PyExc_ValueError, "invalid start argument");
|
||||
return -1;
|
||||
}
|
||||
if (end > PyUnicode_GET_LENGTH(str)) {
|
||||
PyErr_Format(PyExc_ValueError, "invalid end argument");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _PyUnicodeWriter_WriteSubstring((_PyUnicodeWriter*)writer, str,
|
||||
start, end);
|
||||
}
|
||||
|
||||
static inline int
|
||||
PyUnicodeWriter_Format(PyUnicodeWriter *writer, const char *format, ...)
|
||||
{
|
||||
va_list vargs;
|
||||
va_start(vargs, format);
|
||||
PyObject *str = PyUnicode_FromFormatV(format, vargs);
|
||||
va_end(vargs);
|
||||
if (str == _Py_NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
|
||||
Py_DECREF(str);
|
||||
return res;
|
||||
}
|
||||
#endif // PY_VERSION_HEX < 0x030E0000
|
||||
|
||||
// gh-116560 added PyLong_GetSign() to Python 3.14.0a0
|
||||
#if PY_VERSION_HEX < 0x030E00A0
|
||||
|
@ -1354,6 +1524,175 @@ static inline int PyLong_GetSign(PyObject *obj, int *sign)
|
|||
#endif
|
||||
|
||||
|
||||
// gh-124502 added PyUnicode_Equal() to Python 3.14.0a0
|
||||
#if PY_VERSION_HEX < 0x030E00A0
|
||||
static inline int PyUnicode_Equal(PyObject *str1, PyObject *str2)
|
||||
{
|
||||
if (!PyUnicode_Check(str1)) {
|
||||
PyErr_Format(PyExc_TypeError, "first argument must be str, not %s",
|
||||
Py_TYPE(str1)->tp_name);
|
||||
return -1;
|
||||
}
|
||||
if (!PyUnicode_Check(str2)) {
|
||||
PyErr_Format(PyExc_TypeError, "second argument must be str, not %s",
|
||||
Py_TYPE(str2)->tp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION)
|
||||
PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *str1, PyObject *str2);
|
||||
|
||||
return _PyUnicode_Equal(str1, str2);
|
||||
#elif PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION)
|
||||
return _PyUnicode_EQ(str1, str2);
|
||||
#elif PY_VERSION_HEX >= 0x03090000 && defined(PYPY_VERSION)
|
||||
return _PyUnicode_EQ(str1, str2);
|
||||
#else
|
||||
return (PyUnicode_Compare(str1, str2) == 0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// gh-121645 added PyBytes_Join() to Python 3.14.0a0
|
||||
#if PY_VERSION_HEX < 0x030E00A0
|
||||
static inline PyObject* PyBytes_Join(PyObject *sep, PyObject *iterable)
|
||||
{
|
||||
return _PyBytes_Join(sep, iterable);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if PY_VERSION_HEX < 0x030E00A0
|
||||
static inline Py_hash_t Py_HashBuffer(const void *ptr, Py_ssize_t len)
|
||||
{
|
||||
#if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
|
||||
PyAPI_FUNC(Py_hash_t) _Py_HashBytes(const void *src, Py_ssize_t len);
|
||||
|
||||
return _Py_HashBytes(ptr, len);
|
||||
#else
|
||||
Py_hash_t hash;
|
||||
PyObject *bytes = PyBytes_FromStringAndSize((const char*)ptr, len);
|
||||
if (bytes == NULL) {
|
||||
return -1;
|
||||
}
|
||||
hash = PyObject_Hash(bytes);
|
||||
Py_DECREF(bytes);
|
||||
return hash;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if PY_VERSION_HEX < 0x030E00A0
|
||||
static inline int PyIter_NextItem(PyObject *iter, PyObject **item)
|
||||
{
|
||||
iternextfunc tp_iternext;
|
||||
|
||||
assert(iter != NULL);
|
||||
assert(item != NULL);
|
||||
|
||||
tp_iternext = Py_TYPE(iter)->tp_iternext;
|
||||
if (tp_iternext == NULL) {
|
||||
*item = NULL;
|
||||
PyErr_Format(PyExc_TypeError, "expected an iterator, got '%s'",
|
||||
Py_TYPE(iter)->tp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((*item = tp_iternext(iter))) {
|
||||
return 1;
|
||||
}
|
||||
if (!PyErr_Occurred()) {
|
||||
return 0;
|
||||
}
|
||||
if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
|
||||
PyErr_Clear();
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if PY_VERSION_HEX < 0x030E00A0
|
||||
static inline PyObject* PyLong_FromInt32(int32_t value)
|
||||
{
|
||||
Py_BUILD_ASSERT(sizeof(long) >= 4);
|
||||
return PyLong_FromLong(value);
|
||||
}
|
||||
|
||||
static inline PyObject* PyLong_FromInt64(int64_t value)
|
||||
{
|
||||
Py_BUILD_ASSERT(sizeof(long long) >= 8);
|
||||
return PyLong_FromLongLong(value);
|
||||
}
|
||||
|
||||
static inline PyObject* PyLong_FromUInt32(uint32_t value)
|
||||
{
|
||||
Py_BUILD_ASSERT(sizeof(unsigned long) >= 4);
|
||||
return PyLong_FromUnsignedLong(value);
|
||||
}
|
||||
|
||||
static inline PyObject* PyLong_FromUInt64(uint64_t value)
|
||||
{
|
||||
Py_BUILD_ASSERT(sizeof(unsigned long long) >= 8);
|
||||
return PyLong_FromUnsignedLongLong(value);
|
||||
}
|
||||
|
||||
static inline int PyLong_AsInt32(PyObject *obj, int32_t *pvalue)
|
||||
{
|
||||
Py_BUILD_ASSERT(sizeof(int) == 4);
|
||||
int value = PyLong_AsInt(obj);
|
||||
if (value == -1 && PyErr_Occurred()) {
|
||||
return -1;
|
||||
}
|
||||
*pvalue = (int32_t)value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int PyLong_AsInt64(PyObject *obj, int64_t *pvalue)
|
||||
{
|
||||
Py_BUILD_ASSERT(sizeof(long long) == 8);
|
||||
long long value = PyLong_AsLongLong(obj);
|
||||
if (value == -1 && PyErr_Occurred()) {
|
||||
return -1;
|
||||
}
|
||||
*pvalue = (int64_t)value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int PyLong_AsUInt32(PyObject *obj, uint32_t *pvalue)
|
||||
{
|
||||
Py_BUILD_ASSERT(sizeof(long) >= 4);
|
||||
unsigned long value = PyLong_AsUnsignedLong(obj);
|
||||
if (value == (unsigned long)-1 && PyErr_Occurred()) {
|
||||
return -1;
|
||||
}
|
||||
#if SIZEOF_LONG > 4
|
||||
if ((unsigned long)UINT32_MAX < value) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"Python int too large to convert to C uint32_t");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
*pvalue = (uint32_t)value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue)
|
||||
{
|
||||
Py_BUILD_ASSERT(sizeof(long long) == 8);
|
||||
unsigned long long value = PyLong_AsUnsignedLongLong(obj);
|
||||
if (value == (unsigned long long)-1 && PyErr_Occurred()) {
|
||||
return -1;
|
||||
}
|
||||
*pvalue = (uint64_t)value;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue
Block a user