summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Heimes <christian@python.org>2019-09-09 16:06:55 (GMT)
committerSteve Dower <steve.dower@python.org>2019-09-09 16:06:55 (GMT)
commit915cd3f0696cb8a7206754a8fc34d4cd865a1b4a (patch)
treed5dd29a1c76f1ac11ac6a20dc47ccb7faf680200
parent09090d04ef8d2f4c94157b852d3d530a51e13d22 (diff)
downloadcpython-915cd3f0696cb8a7206754a8fc34d4cd865a1b4a.zip
cpython-915cd3f0696cb8a7206754a8fc34d4cd865a1b4a.tar.gz
cpython-915cd3f0696cb8a7206754a8fc34d4cd865a1b4a.tar.bz2
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>
-rw-r--r--Lib/test/test_ssl.py4
-rw-r--r--Modules/_ssl.c55
2 files changed, 29 insertions, 30 deletions
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 6ad0b61..b719283 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -835,8 +835,8 @@ class BasicSocketTests(unittest.TestCase):
cert, enc, trust = element
self.assertIsInstance(cert, bytes)
self.assertIn(enc, {"x509_asn", "pkcs_7_asn"})
- self.assertIsInstance(trust, (set, bool))
- if isinstance(trust, set):
+ self.assertIsInstance(trust, (frozenset, set, bool))
+ if isinstance(trust, (frozenset, set)):
trust_oids.update(trust)
serverAuth = "1.3.6.1.5.5.7.3.1"
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index d94efa9..64060c6 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -5517,7 +5517,7 @@ parseKeyUsage(PCCERT_CONTEXT pCertCtx, DWORD flags)
}
return PyErr_SetFromWindowsErr(error);
}
- retval = PySet_New(NULL);
+ retval = PyFrozenSet_New(NULL);
if (retval == NULL) {
goto error;
}
@@ -5592,19 +5592,6 @@ ssl_collect_certificates(const char *store_name)
return hCollectionStore;
}
-/* code from Objects/listobject.c */
-
-static int
-list_contains(PyListObject *a, PyObject *el)
-{
- Py_ssize_t i;
- int cmp;
-
- for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(a); ++i)
- cmp = PyObject_RichCompareBool(PyList_GET_ITEM(a, i), el, Py_EQ);
- return cmp;
-}
-
/*[clinic input]
_ssl.enum_certificates
store_name: str
@@ -5627,7 +5614,7 @@ _ssl_enum_certificates_impl(PyObject *module, const char *store_name)
PyObject *keyusage = NULL, *cert = NULL, *enc = NULL, *tup = NULL;
PyObject *result = NULL;
- result = PyList_New(0);
+ result = PySet_New(NULL);
if (result == NULL) {
return NULL;
}
@@ -5667,11 +5654,10 @@ _ssl_enum_certificates_impl(PyObject *module, const char *store_name)
enc = NULL;
PyTuple_SET_ITEM(tup, 2, keyusage);
keyusage = NULL;
- if (!list_contains((PyListObject*)result, tup)) {
- if (PyList_Append(result, tup) < 0) {
- Py_CLEAR(result);
- break;
- }
+ if (PySet_Add(result, tup) == -1) {
+ Py_CLEAR(result);
+ Py_CLEAR(tup);
+ break;
}
Py_CLEAR(tup);
}
@@ -5695,7 +5681,14 @@ _ssl_enum_certificates_impl(PyObject *module, const char *store_name)
return PyErr_SetFromWindowsErr(GetLastError());
}
- return result;
+ /* convert set to list */
+ if (result == NULL) {
+ return NULL;
+ } else {
+ PyObject *lst = PySequence_List(result);
+ Py_DECREF(result);
+ return lst;
+ }
}
/*[clinic input]
@@ -5719,7 +5712,7 @@ _ssl_enum_crls_impl(PyObject *module, const char *store_name)
PyObject *crl = NULL, *enc = NULL, *tup = NULL;
PyObject *result = NULL;
- result = PyList_New(0);
+ result = PySet_New(NULL);
if (result == NULL) {
return NULL;
}
@@ -5749,11 +5742,10 @@ _ssl_enum_crls_impl(PyObject *module, const char *store_name)
PyTuple_SET_ITEM(tup, 1, enc);
enc = NULL;
- if (!list_contains((PyListObject*)result, tup)) {
- if (PyList_Append(result, tup) < 0) {
- Py_CLEAR(result);
- break;
- }
+ if (PySet_Add(result, tup) == -1) {
+ Py_CLEAR(result);
+ Py_CLEAR(tup);
+ break;
}
Py_CLEAR(tup);
}
@@ -5775,7 +5767,14 @@ _ssl_enum_crls_impl(PyObject *module, const char *store_name)
Py_XDECREF(result);
return PyErr_SetFromWindowsErr(GetLastError());
}
- return result;
+ /* convert set to list */
+ if (result == NULL) {
+ return NULL;
+ } else {
+ PyObject *lst = PySequence_List(result);
+ Py_DECREF(result);
+ return lst;
+ }
}
#endif /* _MSC_VER */