Skip to content

gh-83004: Clean up refleaks in ssl, socket initialisation #99044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Clean up refleaks on failed module initialisation in in :mod:`_ssl` and :mod:`_socket`
19 changes: 13 additions & 6 deletions Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -5925,8 +5925,7 @@ sslmodule_init_constants(PyObject *m)
#define addbool(m, key, value) \
do { \
PyObject *bool_obj = (value) ? Py_True : Py_False; \
Py_INCREF(bool_obj); \
PyModule_AddObject((m), (key), bool_obj); \
PyModule_AddObjectRef((m), (key), bool_obj); \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this still a leak because we're not checking the return value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's no longer a leak.

The thing that makes PyModule_AddObject tricky cause leaks is that you have to decref in the failure case, but not in the success case (because it steals the ref). With PyModule_AddObjectRef you can treat the failure and success cases the same in terms of what they do to ref counts.

But yes, in general we should probably be propagating failures here, and the other cases below you commented on. I didn't do it in this PR because it's a slightly separate change and there are many other places in this module where we don't check return values.

Copy link
Contributor Author

@hauntsaninja hauntsaninja Nov 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I check return values for just the ones I'm touching in this PR or fix all of them?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation! I feel it'd be fine to also fix missing error checks in this PR, since the change remains localized and you're fixing a very similar problem to what the PR already fixes.

} while (0)

addbool(m, "HAS_SNI", 1);
Expand Down Expand Up @@ -6059,23 +6058,31 @@ sslmodule_init_versioninfo(PyObject *m)
*/
libver = OpenSSL_version_num();
r = PyLong_FromUnsignedLong(libver);
if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r))
if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r)) {
Py_XDECREF(r);
return -1;
}

parse_openssl_version(libver, &major, &minor, &fix, &patch, &status);
r = Py_BuildValue("IIIII", major, minor, fix, patch, status);
if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r))
if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r)) {
Py_XDECREF(r);
return -1;
}

r = PyUnicode_FromString(OpenSSL_version(OPENSSL_VERSION));
if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r))
if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) {
Py_XDECREF(r);
return -1;
}

libver = OPENSSL_VERSION_NUMBER;
parse_openssl_version(libver, &major, &minor, &fix, &patch, &status);
r = Py_BuildValue("IIIII", major, minor, fix, patch, status);
if (r == NULL || PyModule_AddObject(m, "_OPENSSL_API_VERSION", r))
if (r == NULL || PyModule_AddObject(m, "_OPENSSL_API_VERSION", r)) {
Py_XDECREF(r);
return -1;
}

return 0;
}
Expand Down
31 changes: 14 additions & 17 deletions Modules/socketmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -7342,38 +7342,34 @@ PyInit__socket(void)
if (m == NULL)
return NULL;

Py_INCREF(PyExc_OSError);
PyModule_AddObject(m, "error", PyExc_OSError);
if (PyModule_AddObjectRef(m, "error", PyExc_OSError) != 0)
return NULL;
socket_herror = PyErr_NewException("socket.herror",
PyExc_OSError, NULL);
if (socket_herror == NULL)
return NULL;
Py_INCREF(socket_herror);
PyModule_AddObject(m, "herror", socket_herror);
if (PyModule_AddObjectRef(m, "herror", socket_herror) != 0)
return NULL;
socket_gaierror = PyErr_NewException("socket.gaierror", PyExc_OSError,
NULL);
NULL);
if (socket_gaierror == NULL)
return NULL;
Py_INCREF(socket_gaierror);
PyModule_AddObject(m, "gaierror", socket_gaierror);
PyModule_AddObjectRef(m, "timeout", PyExc_TimeoutError);
if (PyModule_AddObjectRef(m, "gaierror", socket_gaierror) != 0)
return NULL;
if (PyModule_AddObjectRef(m, "timeout", PyExc_TimeoutError) != 0)
return NULL;

Py_INCREF((PyObject *)&sock_type);
if (PyModule_AddObject(m, "SocketType",
(PyObject *)&sock_type) != 0)
if (PyModule_AddObjectRef(m, "SocketType", (PyObject *)&sock_type) != 0)
return NULL;
Py_INCREF((PyObject *)&sock_type);
if (PyModule_AddObject(m, "socket",
(PyObject *)&sock_type) != 0)
if (PyModule_AddObjectRef(m, "socket", (PyObject *)&sock_type) != 0)
return NULL;

#ifdef ENABLE_IPV6
has_ipv6 = Py_True;
#else
has_ipv6 = Py_False;
#endif
Py_INCREF(has_ipv6);
PyModule_AddObject(m, "has_ipv6", has_ipv6);
PyModule_AddObjectRef(m, "has_ipv6", has_ipv6);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the return value.


/* Export C API */
PySocketModule_APIObject *capi = sock_get_api();
Expand Down Expand Up @@ -8666,7 +8662,8 @@ PyInit__socket(void)
tmp = PyLong_FromUnsignedLong(codes[i]);
if (tmp == NULL)
return NULL;
PyModule_AddObject(m, names[i], tmp);
PyModule_AddObjectRef(m, names[i], tmp);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here too.

Py_DECREF(tmp);
}
}
PyModule_AddIntMacro(m, RCVALL_OFF);
Expand Down