Skip to content

Commit a6e73a6

Browse files
committed
bpo-35941: Fix performance regression in new code
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 9d60706 commit a6e73a6

1 file changed

Lines changed: 27 additions & 28 deletions

File tree

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
}
@@ -5591,19 +5591,6 @@ ssl_collect_certificates(const char *store_name)
55915591
return hCollectionStore;
55925592
}
55935593

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

5629-
result = PyList_New(0);
5616+
result = PySet_New(NULL);
56305617
if (result == NULL) {
56315618
return NULL;
56325619
}
@@ -5666,11 +5653,10 @@ _ssl_enum_certificates_impl(PyObject *module, const char *store_name)
56665653
enc = NULL;
56675654
PyTuple_SET_ITEM(tup, 2, keyusage);
56685655
keyusage = NULL;
5669-
if (!list_contains((PyListObject*)result, tup)) {
5670-
if (PyList_Append(result, tup) < 0) {
5671-
Py_CLEAR(result);
5672-
break;
5673-
}
5656+
if (PySet_Add(result, tup) == -1) {
5657+
Py_CLEAR(result);
5658+
Py_CLEAR(tup);
5659+
break;
56745660
}
56755661
Py_CLEAR(tup);
56765662
}
@@ -5694,7 +5680,14 @@ _ssl_enum_certificates_impl(PyObject *module, const char *store_name)
56945680
return PyErr_SetFromWindowsErr(GetLastError());
56955681
}
56965682

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

57005693
/*[clinic input]
@@ -5718,7 +5711,7 @@ _ssl_enum_crls_impl(PyObject *module, const char *store_name)
57185711
PyObject *crl = NULL, *enc = NULL, *tup = NULL;
57195712
PyObject *result = NULL;
57205713

5721-
result = PyList_New(0);
5714+
result = PySet_New(NULL);
57225715
if (result == NULL) {
57235716
return NULL;
57245717
}
@@ -5748,11 +5741,10 @@ _ssl_enum_crls_impl(PyObject *module, const char *store_name)
57485741
PyTuple_SET_ITEM(tup, 1, enc);
57495742
enc = NULL;
57505743

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

57805779
#endif /* _MSC_VER */

0 commit comments

Comments
 (0)