Skip to content

Commit 915cd3f

Browse files
tiranzooba
authored andcommitted
bpo-35941: Fix performance regression in new code (GH-12610)
Accumulate certificates in a set instead of doing a costly list contain operation. A Windows cert store can easily contain over hundred certificates. The old code would result in way over 5,000 comparison operations Signed-off-by: Christian Heimes <christian@python.org>
1 parent 09090d0 commit 915cd3f

File tree

2 files changed

+29
-30
lines changed

2 files changed

+29
-30
lines changed

Lib/test/test_ssl.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -835,8 +835,8 @@ def test_enum_certificates(self):
835835
cert, enc, trust = element
836836
self.assertIsInstance(cert, bytes)
837837
self.assertIn(enc, {"x509_asn", "pkcs_7_asn"})
838-
self.assertIsInstance(trust, (set, bool))
839-
if isinstance(trust, set):
838+
self.assertIsInstance(trust, (frozenset, set, bool))
839+
if isinstance(trust, (frozenset, set)):
840840
trust_oids.update(trust)
841841

842842
serverAuth = "1.3.6.1.5.5.7.3.1"

Modules/_ssl.c

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5517,7 +5517,7 @@ parseKeyUsage(PCCERT_CONTEXT pCertCtx, DWORD flags)
55175517
}
55185518
return PyErr_SetFromWindowsErr(error);
55195519
}
5520-
retval = PySet_New(NULL);
5520+
retval = PyFrozenSet_New(NULL);
55215521
if (retval == NULL) {
55225522
goto error;
55235523
}
@@ -5592,19 +5592,6 @@ ssl_collect_certificates(const char *store_name)
55925592
return hCollectionStore;
55935593
}
55945594

5595-
/* code from Objects/listobject.c */
5596-
5597-
static int
5598-
list_contains(PyListObject *a, PyObject *el)
5599-
{
5600-
Py_ssize_t i;
5601-
int cmp;
5602-
5603-
for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(a); ++i)
5604-
cmp = PyObject_RichCompareBool(PyList_GET_ITEM(a, i), el, Py_EQ);
5605-
return cmp;
5606-
}
5607-
56085595
/*[clinic input]
56095596
_ssl.enum_certificates
56105597
store_name: str
@@ -5627,7 +5614,7 @@ _ssl_enum_certificates_impl(PyObject *module, const char *store_name)
56275614
PyObject *keyusage = NULL, *cert = NULL, *enc = NULL, *tup = NULL;
56285615
PyObject *result = NULL;
56295616

5630-
result = PyList_New(0);
5617+
result = PySet_New(NULL);
56315618
if (result == NULL) {
56325619
return NULL;
56335620
}
@@ -5667,11 +5654,10 @@ _ssl_enum_certificates_impl(PyObject *module, const char *store_name)
56675654
enc = NULL;
56685655
PyTuple_SET_ITEM(tup, 2, keyusage);
56695656
keyusage = NULL;
5670-
if (!list_contains((PyListObject*)result, tup)) {
5671-
if (PyList_Append(result, tup) < 0) {
5672-
Py_CLEAR(result);
5673-
break;
5674-
}
5657+
if (PySet_Add(result, tup) == -1) {
5658+
Py_CLEAR(result);
5659+
Py_CLEAR(tup);
5660+
break;
56755661
}
56765662
Py_CLEAR(tup);
56775663
}
@@ -5695,7 +5681,14 @@ _ssl_enum_certificates_impl(PyObject *module, const char *store_name)
56955681
return PyErr_SetFromWindowsErr(GetLastError());
56965682
}
56975683

5698-
return result;
5684+
/* convert set to list */
5685+
if (result == NULL) {
5686+
return NULL;
5687+
} else {
5688+
PyObject *lst = PySequence_List(result);
5689+
Py_DECREF(result);
5690+
return lst;
5691+
}
56995692
}
57005693

57015694
/*[clinic input]
@@ -5719,7 +5712,7 @@ _ssl_enum_crls_impl(PyObject *module, const char *store_name)
57195712
PyObject *crl = NULL, *enc = NULL, *tup = NULL;
57205713
PyObject *result = NULL;
57215714

5722-
result = PyList_New(0);
5715+
result = PySet_New(NULL);
57235716
if (result == NULL) {
57245717
return NULL;
57255718
}
@@ -5749,11 +5742,10 @@ _ssl_enum_crls_impl(PyObject *module, const char *store_name)
57495742
PyTuple_SET_ITEM(tup, 1, enc);
57505743
enc = NULL;
57515744

5752-
if (!list_contains((PyListObject*)result, tup)) {
5753-
if (PyList_Append(result, tup) < 0) {
5754-
Py_CLEAR(result);
5755-
break;
5756-
}
5745+
if (PySet_Add(result, tup) == -1) {
5746+
Py_CLEAR(result);
5747+
Py_CLEAR(tup);
5748+
break;
57575749
}
57585750
Py_CLEAR(tup);
57595751
}
@@ -5775,7 +5767,14 @@ _ssl_enum_crls_impl(PyObject *module, const char *store_name)
57755767
Py_XDECREF(result);
57765768
return PyErr_SetFromWindowsErr(GetLastError());
57775769
}
5778-
return result;
5770+
/* convert set to list */
5771+
if (result == NULL) {
5772+
return NULL;
5773+
} else {
5774+
PyObject *lst = PySequence_List(result);
5775+
Py_DECREF(result);
5776+
return lst;
5777+
}
57795778
}
57805779

57815780
#endif /* _MSC_VER */

0 commit comments

Comments
 (0)