Skip to content

Commit

Permalink
PUll in main
Browse files Browse the repository at this point in the history
  • Loading branch information
erlend-aasland committed Feb 16, 2024
2 parents 8b7dde7 + 351c103 commit 7720c66
Show file tree
Hide file tree
Showing 16 changed files with 191 additions and 98 deletions.
23 changes: 15 additions & 8 deletions Include/internal/pycore_freelist.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extern "C" {

struct _Py_list_freelist {
#ifdef WITH_FREELISTS
PyListObject *free_list[PyList_MAXFREELIST];
PyListObject *items[PyList_MAXFREELIST];
int numfree;
#endif
};
Expand All @@ -50,7 +50,7 @@ struct _Py_tuple_freelist {
object is used as the linked list node, with its first item
(ob_item[0]) pointing to the next node (i.e. the previous head).
Each linked list is initially NULL. */
PyTupleObject *free_list[PyTuple_NFREELISTS];
PyTupleObject *items[PyTuple_NFREELISTS];
int numfree[PyTuple_NFREELISTS];
#else
char _unused; // Empty structs are not allowed.
Expand All @@ -63,17 +63,23 @@ struct _Py_float_freelist {
free_list is a singly-linked list of available PyFloatObjects,
linked via abuse of their ob_type members. */
int numfree;
PyFloatObject *free_list;
PyFloatObject *items;
#endif
};

struct _Py_dict_freelist {
#ifdef WITH_FREELISTS
/* Dictionary reuse scheme to save calls to malloc and free */
PyDictObject *free_list[PyDict_MAXFREELIST];
PyDictKeysObject *keys_free_list[PyDict_MAXFREELIST];
PyDictObject *items[PyDict_MAXFREELIST];
int numfree;
#endif
};

struct _Py_dictkeys_freelist {
#ifdef WITH_FREELISTS
/* Dictionary keys reuse scheme to save calls to malloc and free */
PyDictKeysObject *items[PyDict_MAXFREELIST];
int numfree;
int keys_numfree;
#endif
};

Expand All @@ -88,7 +94,7 @@ struct _Py_slice_freelist {
struct _Py_context_freelist {
#ifdef WITH_FREELISTS
// List of free PyContext objects
PyContext *freelist;
PyContext *items;
int numfree;
#endif
};
Expand All @@ -110,7 +116,7 @@ struct _Py_async_gen_freelist {
struct _PyObjectStackChunk;

struct _Py_object_stack_freelist {
struct _PyObjectStackChunk *free_list;
struct _PyObjectStackChunk *items;
Py_ssize_t numfree;
};

Expand All @@ -119,6 +125,7 @@ struct _Py_object_freelists {
struct _Py_tuple_freelist tuples;
struct _Py_list_freelist lists;
struct _Py_dict_freelist dicts;
struct _Py_dictkeys_freelist dictkeys;
struct _Py_slice_freelist slices;
struct _Py_context_freelist contexts;
struct _Py_async_gen_freelist async_gens;
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_typeobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ struct _types_runtime_state {
// bpo-42745: next_version_tag remains shared by all interpreters
// because of static types.
unsigned int next_version_tag;
PyMutex type_mutex;
};


Expand Down Expand Up @@ -71,6 +70,7 @@ struct types_state {
struct type_cache type_cache;
size_t num_builtins_initialized;
static_builtin_state builtins[_Py_MAX_STATIC_BUILTIN_TYPES];
PyMutex mutex;
};


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
:meth:`ssl.SSLContext.cert_store_stats` and
:meth:`ssl.SSLContext.get_ca_certs` now correctly lock access to the
certificate store, when the :class:`ssl.SSLContext` is shared across
multiple threads.
65 changes: 60 additions & 5 deletions Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -4553,6 +4553,50 @@ set_sni_callback(PySSLContext *self, PyObject *arg, void *c)
return 0;
}

#if OPENSSL_VERSION_NUMBER < 0x30300000L
static X509_OBJECT *x509_object_dup(const X509_OBJECT *obj)
{
int ok;
X509_OBJECT *ret = X509_OBJECT_new();
if (ret == NULL) {
return NULL;
}
switch (X509_OBJECT_get_type(obj)) {
case X509_LU_X509:
ok = X509_OBJECT_set1_X509(ret, X509_OBJECT_get0_X509(obj));
break;
case X509_LU_CRL:
/* X509_OBJECT_get0_X509_CRL was not const-correct prior to 3.0.*/
ok = X509_OBJECT_set1_X509_CRL(
ret, X509_OBJECT_get0_X509_CRL((X509_OBJECT *)obj));
break;
default:
/* We cannot duplicate unrecognized types in a polyfill, but it is
* safe to leave an empty object. The caller will ignore it. */
ok = 1;
break;
}
if (!ok) {
X509_OBJECT_free(ret);
return NULL;
}
return ret;
}

static STACK_OF(X509_OBJECT) *
X509_STORE_get1_objects(X509_STORE *store)
{
STACK_OF(X509_OBJECT) *ret;
if (!X509_STORE_lock(store)) {
return NULL;
}
ret = sk_X509_OBJECT_deep_copy(X509_STORE_get0_objects(store),
x509_object_dup, X509_OBJECT_free);
X509_STORE_unlock(store);
return ret;
}
#endif

PyDoc_STRVAR(PySSLContext_sni_callback_doc,
"Set a callback that will be called when a server name is provided by the SSL/TLS client in the SNI extension.\n\
\n\
Expand Down Expand Up @@ -4582,7 +4626,12 @@ _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self)
int x509 = 0, crl = 0, ca = 0, i;

store = SSL_CTX_get_cert_store(self->ctx);
objs = X509_STORE_get0_objects(store);
objs = X509_STORE_get1_objects(store);
if (objs == NULL) {
PyErr_SetString(PyExc_MemoryError, "failed to query cert store");
return NULL;
}

for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
obj = sk_X509_OBJECT_value(objs, i);
switch (X509_OBJECT_get_type(obj)) {
Expand All @@ -4596,12 +4645,11 @@ _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self)
crl++;
break;
default:
/* Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY.
* As far as I can tell they are internal states and never
* stored in a cert store */
/* Ignore unrecognized types. */
break;
}
}
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
return Py_BuildValue("{sisisi}", "x509", x509, "crl", crl,
"x509_ca", ca);
}
Expand Down Expand Up @@ -4633,7 +4681,12 @@ _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form)
}

store = SSL_CTX_get_cert_store(self->ctx);
objs = X509_STORE_get0_objects(store);
objs = X509_STORE_get1_objects(store);
if (objs == NULL) {
PyErr_SetString(PyExc_MemoryError, "failed to query cert store");
goto error;
}

for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
X509_OBJECT *obj;
X509 *cert;
Expand Down Expand Up @@ -4661,9 +4714,11 @@ _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form)
}
Py_CLEAR(ci);
}
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
return rlist;

error:
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
Py_XDECREF(ci);
Py_XDECREF(rlist);
return NULL;
Expand Down
51 changes: 31 additions & 20 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,25 +276,33 @@ get_dict_freelist(void)
struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
return &freelists->dicts;
}

static struct _Py_dictkeys_freelist *
get_dictkeys_freelist(void)
{
struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
return &freelists->dictkeys;
}
#endif


void
_PyDict_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization)
{
#ifdef WITH_FREELISTS
struct _Py_dict_freelist *state = &freelists->dicts;
while (state->numfree > 0) {
PyDictObject *op = state->free_list[--state->numfree];
struct _Py_dict_freelist *freelist = &freelists->dicts;
while (freelist->numfree > 0) {
PyDictObject *op = freelist->items[--freelist->numfree];
assert(PyDict_CheckExact(op));
PyObject_GC_Del(op);
}
while (state->keys_numfree > 0) {
PyMem_Free(state->keys_free_list[--state->keys_numfree]);
struct _Py_dictkeys_freelist *keys_freelist = &freelists->dictkeys;
while (keys_freelist->numfree > 0) {
PyMem_Free(keys_freelist->items[--keys_freelist->numfree]);
}
if (is_finalization) {
state->numfree = -1;
state->keys_numfree = -1;
freelist->numfree = -1;
keys_freelist->numfree = -1;
}
#endif
}
Expand All @@ -314,6 +322,9 @@ _PyDict_DebugMallocStats(FILE *out)
struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
_PyDebugAllocatorStats(out, "free PyDictObject",
dict_freelist->numfree, sizeof(PyDictObject));
struct _Py_dictkeys_freelist *dictkeys_freelist = get_dictkeys_freelist();
_PyDebugAllocatorStats(out, "free PyDictKeysObject",
dictkeys_freelist->numfree, sizeof(PyDictKeysObject));
#endif
}

Expand Down Expand Up @@ -663,9 +674,9 @@ new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode)
}

#ifdef WITH_FREELISTS
struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
if (log2_size == PyDict_LOG_MINSIZE && unicode && dict_freelist->keys_numfree > 0) {
dk = dict_freelist->keys_free_list[--dict_freelist->keys_numfree];
struct _Py_dictkeys_freelist *freelist = get_dictkeys_freelist();
if (log2_size == PyDict_LOG_MINSIZE && unicode && freelist->numfree > 0) {
dk = freelist->items[--freelist->numfree];
OBJECT_STAT_INC(from_freelist);
}
else
Expand Down Expand Up @@ -698,12 +709,12 @@ static void
free_keys_object(PyDictKeysObject *keys)
{
#ifdef WITH_FREELISTS
struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
struct _Py_dictkeys_freelist *freelist = get_dictkeys_freelist();
if (DK_LOG_SIZE(keys) == PyDict_LOG_MINSIZE
&& dict_freelist->keys_numfree < PyDict_MAXFREELIST
&& dict_freelist->keys_numfree >= 0
&& freelist->numfree < PyDict_MAXFREELIST
&& freelist->numfree >= 0
&& DK_IS_UNICODE(keys)) {
dict_freelist->keys_free_list[dict_freelist->keys_numfree++] = keys;
freelist->items[freelist->numfree++] = keys;
OBJECT_STAT_INC(to_freelist);
return;
}
Expand Down Expand Up @@ -743,9 +754,9 @@ new_dict(PyInterpreterState *interp,
PyDictObject *mp;
assert(keys != NULL);
#ifdef WITH_FREELISTS
struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
if (dict_freelist->numfree > 0) {
mp = dict_freelist->free_list[--dict_freelist->numfree];
struct _Py_dict_freelist *freelist = get_dict_freelist();
if (freelist->numfree > 0) {
mp = freelist->items[--freelist->numfree];
assert (mp != NULL);
assert (Py_IS_TYPE(mp, &PyDict_Type));
OBJECT_STAT_INC(from_freelist);
Expand Down Expand Up @@ -2593,10 +2604,10 @@ dict_dealloc(PyObject *self)
dictkeys_decref(interp, keys);
}
#ifdef WITH_FREELISTS
struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
if (dict_freelist->numfree < PyDict_MAXFREELIST && dict_freelist->numfree >=0 &&
struct _Py_dict_freelist *freelist = get_dict_freelist();
if (freelist->numfree < PyDict_MAXFREELIST && freelist->numfree >=0 &&
Py_IS_TYPE(mp, &PyDict_Type)) {
dict_freelist->free_list[dict_freelist->numfree++] = mp;
freelist->items[freelist->numfree++] = mp;
OBJECT_STAT_INC(to_freelist);
}
else
Expand Down
12 changes: 6 additions & 6 deletions Objects/floatobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,9 @@ PyFloat_FromDouble(double fval)
PyFloatObject *op;
#ifdef WITH_FREELISTS
struct _Py_float_freelist *float_freelist = get_float_freelist();
op = float_freelist->free_list;
op = float_freelist->items;
if (op != NULL) {
float_freelist->free_list = (PyFloatObject *) Py_TYPE(op);
float_freelist->items = (PyFloatObject *) Py_TYPE(op);
float_freelist->numfree--;
OBJECT_STAT_INC(from_freelist);
}
Expand Down Expand Up @@ -251,8 +251,8 @@ _PyFloat_ExactDealloc(PyObject *obj)
return;
}
float_freelist->numfree++;
Py_SET_TYPE(op, (PyTypeObject *)float_freelist->free_list);
float_freelist->free_list = op;
Py_SET_TYPE(op, (PyTypeObject *)float_freelist->items);
float_freelist->items = op;
OBJECT_STAT_INC(to_freelist);
#else
PyObject_Free(op);
Expand Down Expand Up @@ -1994,13 +1994,13 @@ _PyFloat_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalizati
{
#ifdef WITH_FREELISTS
struct _Py_float_freelist *state = &freelists->floats;
PyFloatObject *f = state->free_list;
PyFloatObject *f = state->items;
while (f != NULL) {
PyFloatObject *next = (PyFloatObject*) Py_TYPE(f);
PyObject_Free(f);
f = next;
}
state->free_list = NULL;
state->items = NULL;
if (is_finalization) {
state->numfree = -1;
}
Expand Down
6 changes: 3 additions & 3 deletions Objects/listobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ _PyList_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalizatio
#ifdef WITH_FREELISTS
struct _Py_list_freelist *state = &freelists->lists;
while (state->numfree > 0) {
PyListObject *op = state->free_list[--state->numfree];
PyListObject *op = state->items[--state->numfree];
assert(PyList_CheckExact(op));
PyObject_GC_Del(op);
}
Expand Down Expand Up @@ -169,7 +169,7 @@ PyList_New(Py_ssize_t size)
struct _Py_list_freelist *list_freelist = get_list_freelist();
if (PyList_MAXFREELIST && list_freelist->numfree > 0) {
list_freelist->numfree--;
op = list_freelist->free_list[list_freelist->numfree];
op = list_freelist->items[list_freelist->numfree];
OBJECT_STAT_INC(from_freelist);
_Py_NewReference((PyObject *)op);
}
Expand Down Expand Up @@ -401,7 +401,7 @@ list_dealloc(PyObject *self)
#ifdef WITH_FREELISTS
struct _Py_list_freelist *list_freelist = get_list_freelist();
if (list_freelist->numfree < PyList_MAXFREELIST && list_freelist->numfree >= 0 && PyList_CheckExact(op)) {
list_freelist->free_list[list_freelist->numfree++] = op;
list_freelist->items[list_freelist->numfree++] = op;
OBJECT_STAT_INC(to_freelist);
}
else
Expand Down
Loading

0 comments on commit 7720c66

Please sign in to comment.