diff options
author | Christian Heimes <christian@python.org> | 2019-09-09 16:06:55 (GMT) |
---|---|---|
committer | Steve Dower <steve.dower@python.org> | 2019-09-09 16:06:55 (GMT) |
commit | 915cd3f0696cb8a7206754a8fc34d4cd865a1b4a (patch) | |
tree | d5dd29a1c76f1ac11ac6a20dc47ccb7faf680200 | |
parent | 09090d04ef8d2f4c94157b852d3d530a51e13d22 (diff) | |
download | cpython-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.py | 4 | ||||
-rw-r--r-- | Modules/_ssl.c | 55 |
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 */ |